home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / FAQSYS18.ZIP / FAQS.DAT / PMODE.DOC < prev    next >
Text File  |  1996-01-04  |  99KB  |  2,269 lines

  1.  
  2.   This is the documentation for PMODE 3.0 DPMI/VCPI/XMS/raw protected mode
  3. interface kernel. Copyright (c) 1994, Tran (a.k.a. Thomas Pytel). PMODE is
  4. publicly available and is not confidential or proprietary. I, Thomas Pytel,
  5. reserve all rights to the source code. However, feel free to use or distribute
  6. it in any manner you wish (there is a minor restriction as of November of
  7. 1994, read about it in the Disclaimer section). All I ask, if you use this
  8. code in some production, is credits for it.
  9.  
  10. ------------------------------------------------------------------------------
  11. Contents:
  12. ---------
  13.  
  14.   0 - Introduction
  15.       0.0 - Disclaimer
  16.       0.1 - Description
  17.   1 - Overview
  18.       1.0 - Initialization and termination
  19.       1.1 - Segments, selectors, and descriptors
  20.       1.2 - Stacks and mode switching
  21.       1.3 - Interrupts
  22.       1.4 - Real mode callbacks
  23.       1.5 - PMODE specifics
  24.       1.6 - PMODE internal stacks
  25.   2 - Functions
  26.       2.0 - Function 0000h - Allocate Descriptors
  27.       2.1 - Function 0001h - Free Descriptor
  28.       2.2 - Function 0003h - Get Selector Increment Value
  29.       2.3 - Function 0006h - Get Segment Base Address
  30.       2.4 - Function 0007h - Set Segment Base Address
  31.       2.5 - Function 0008h - Set Segment Limit
  32.       2.6 - Function 0009h - Set Descriptor Access Rights
  33.       2.7 - Function 000Ah - Create Alias Descriptor
  34.       2.8 - Function 000Bh - Get Descriptor
  35.       2.9 - Function 000Ch - Set Descriptor
  36.       2.10 - Function 000Eh - Get Multiple Descriptors
  37.       2.11 - Function 000Fh - Set Multiple Descriptors
  38.       2.12 - Function 0200h - Get Real Mode Interrupt Vector
  39.       2.13 - Function 0201h - Set Real Mode Interrupt Vector
  40.       2.14 - Function 0204h - Get Protected Mode Interrupt Vector
  41.       2.15 - Function 0205h - Set Protected Mode Interrupt Vector
  42.       2.16 - Function 0300h - Simulate Real Mode Interrupt
  43.       2.17 - Function 0301h - Call Real Mode Procedure With Far Return Frame
  44.       2.18 - Function 0302h - Call Real Mode Procedure With IRET Frame
  45.       2.19 - Function 0303h - Allocate Real Mode Callback Address
  46.       2.20 - Function 0304h - Free Real Mode Callback Address
  47.       2.21 - Function 0305h - Get State Save/Restore Addresses
  48.       2.22 - Function 0306h - Get Raw Mode Switch Addresses
  49.       2.23 - Function 0400h - Get Version
  50.       2.24 - Function 0500h - Get Free Memory Information
  51.       2.25 - Function 0501h - Allocate Memory Block
  52.       2.26 - Function 0502h - Free Memory Block
  53.       2.27 - Function 0503h - Resize Memory Block
  54.       2.28 - Function 050Ah - Get Memory Block Size and Base
  55.       2.29 - Function 0900h - Get and Disable Virtual Interrupt State
  56.       2.30 - Function 0901h - Get and Enable Virtual Interrupt State
  57.       2.31 - Function 0902h - Get Virtual Interrupt State
  58.   3 - Miscellaneous
  59.       3.0 - Updates
  60.       3.1 - Glossary
  61.       3.2 - Differences among modes
  62.       3.3 - Notes
  63.       3.4 - Final word
  64.  
  65. ------------------------------------------------------------------------------
  66. 0 - Introduction:
  67. -----------------
  68.  
  69.   This document will not attempt to explain the workings of protected mode. If
  70. you are new to protected mode coding, I suggest you get yourself a good book.
  71. I also suggest you get your hands on some good DPMI documentation as a
  72. reference and background for understanding PMODE. This document is only
  73. intended to explain the workings of PMODE for the purpose of using it directly
  74. or for writing a shell or high level language interface.
  75.  
  76. 0.0 Disclaimer:
  77. ---------------
  78.  
  79. Legal:
  80.  
  81.   I exclude any and all implied warranties, including warranties of
  82. merchantability and fitness for a particular purpose. I make no warranty or
  83. representation, either express or implied, with respect to this source code,
  84. its quality, performance, merchantability, or fitness for a particular
  85. purpose. I shall have no liability for special, incidental, or consequential
  86. damages arising out of or resulting from the use or modification of this
  87. source code.
  88.  
  89. English:
  90.  
  91.   If you fuck up, its your own problem.
  92.  
  93. Also:
  94.  
  95.   There is one restriction to the use of PMODE. You may not sell PMODE for
  96. profit or use it as the kernel of an extender to be sold for profit. You MAY
  97. use it in your own for profit productions, as long as they are not an extender
  98. in and of itself. This means you can use it in games, demos, business
  99. applications, etc... without worry or financlai obligation to me. You CAN use
  100. PMODE in a larger extender provided that you do not sell that extender for
  101. profit. You may use that extender for your own for profit productions, or
  102. distribute it as freeware, but you may NOT charge money for its use anywhere.
  103.  
  104. 0.1 Description:
  105. ----------------
  106.  
  107.   PMODE 3.0 is basically a DOS extender. It allows DOS programs to run in full
  108. protected mode. PMODE will take care of all the system details, the descriptor
  109. tables, extended memory management, interrupts, etc... It does not matter what
  110. kind of system is already in place. DPMI, VCPI, XMS, and a clean system will
  111. all be handled appropriately. If DPMI is in place, PMODE will do basically
  112. nothing, and your code will be talking directly to the DPMI host. But if it is
  113. not, PMODE will provide a subset of DPMI functionality to your code. It is
  114. slightly annoying that most of the DPMI interface uses pairs of 16bit
  115. registers for 32bit values. This goes back to the 80286 support of DPMI.
  116.  
  117.   Code using PMODE can set up its own descriptors. It can run across real
  118. mode, 16bit protected mode, and 32bit protected mode. Full extended memory
  119. management is provided. Blocks of extended memory can be allocated, resized,
  120. and freed. PMODE does not manage low memory, Your code is responsible for the
  121. memory below the 1M boundary. The PMODE kernel is well suited for a shell to
  122. extend its functionality. A shell to provide extended or simplified services
  123. to assembly or high level code.
  124.  
  125.   I wrote PMODE with attention to speed. Wherever I could control it, I tried
  126. to ensure that code using PMODE would run as fast as possible. I also tried to
  127. make sure PMODE is very stable. Under DPMI, your code is a slave to the DPMI
  128. host's whims. Almost definately running at CPL 3, which makes it quite slow.
  129. There is nothing I can do about that. Well, locating and messing with the DPMI
  130. host's system tables might not be too hard, but too unpredictable. Running in
  131. protected mode at CPL 3 is better than real mode CPL 3, because you can avoid
  132. loading segment registers very often (which is slow) by setting up flat
  133. memory. However, if DPMI is not present, you can be sure your code will be
  134. running as fast as it possibly can. Under a VCPI, XMS, or raw system, PMODE
  135. will run your code at CPL 0. There are no I/O permission bitmap checks on port
  136. accesses or task switching. Under an XMS or raw system, real mode calls are
  137. executed in actual real mode rather than the slower V86 mode, which is
  138. actually protected mode at CPL 3. Under VCPI, real mode calls are executed in
  139. V86 mode, which is what the VCPI server normally runs DOS in. Also, under
  140. VCPI, paging is enabled. It is a minor speed degredation factor, but one that
  141. is avoided under XMS or raw.
  142.  
  143.   I've been coding 386 protected mode systems for a couple of years now. I
  144. tried to make PMODE as clean as possible. But it was coded from scratch.
  145. Though I tested it extensively, there is unfortunately always the possibility
  146. of a bug. I am pretty confident it is clean though, because I went over EVERY
  147. line of code when finally done with it. I also plugged it into some old
  148. programs using a previous version of PMODE, which did well to help me find a
  149. few bugs.
  150.  
  151. ------------------------------------------------------------------------------
  152. 1 - Overview:
  153. -------------
  154.  
  155.   I adopted the DPMI interface for PMODE to make code that works with PMODE
  156. very portable to other extenders. Only a subset of DPMI is supported, both to
  157. keep the size of the kernel down, and because I am lazy (the latter being the
  158. more important factor). The interface to PMODE is INT 31h in protected mode.
  159. Functions are available for descriptors, interrupt vectors, extended memory,
  160. real mode callbacks, and calling real mode interrupts and procedures. PMODE
  161. works as a subset of DPMI 1.0 rather than DPMI 0.9. This means that error
  162. codes are returned from unsuccessful function calls, and some functions are
  163. available that are not available under DPMI 0.9. Note though, that if the
  164. system is already under DPMI 0.9, PMODE code is not active, so error codes
  165. will not be returned and only DPMI 0.9 functions will be available.
  166.  
  167. 1.0 - Initialization and termination:
  168. -------------------------------------
  169.  
  170.   There are only two functions immediately callable in PMODE. They are
  171. _pm_info and _pm_init. _pm_info returns some information about the current
  172. type of system and the low memory requirements for protected mode. No matter
  173. what the system, DPMI, VCPI, XMS, or raw, a low memory buffer is required for
  174. protected mode operation. The size of this buffer is returned from _pm_info.
  175. Your code is responsible for providing that buffer to _pm_init.
  176.  
  177.   _pm_init switches the system into protected mode. If DPMI is in place, all
  178. that is done is a switch into 32bit protected mode. If the DPMI host does not
  179. support 32bit protected mode, _pm_init will return an error. 32bit protected
  180. mode does not necessarily mean your code has to run in a 32bit segment with
  181. default 32bit instructions, it just means that it is possible. Since DPMI is
  182. defined for 80286 computers, you might even find DPMI that is capable of 32bit
  183. protected mode refusing this request on a 386 system.
  184.  
  185.   _pm_init will return with the carry flag set and an error code in AX if an
  186. error ocurred while trying to switch into protected mode. If the switch to
  187. protected mode was successful, the carry flag will be clear, and the system
  188. will be in protected mode. The CS segment register will have been converted
  189. to a protected mode selector corresponding to a descriptor mapping the same
  190. memory as it did in real mode. Likewise, the DS and SS segment registers will
  191. be converted to selectors. If DS and SS were equal before the call to
  192. _pm_init, the same selector may be returned in both. ES will contain a
  193. selector for your program's PSP. The environment segment at PSP:2ch will also
  194. be converted to a selector if it was a non-zero value before the call to
  195. _pm_init. FS and GS will be returned as 0 (NULL selector). Your code will now
  196. be running in a 16bit protected mode code segment, with full access to the
  197. protected mode INT 31h functions. If the system is DPMI, this is the last your
  198. code will have talked to PMODE, and from now on, will be using the DPMI host
  199. directly.
  200.  
  201. Both functions are FAR, and the full calling format is as follows:
  202.  
  203. ) _pm_info - Get protected mode info:
  204.   In:
  205.     None
  206.   Out:
  207.     AX - return code:
  208.       0000h - successful
  209.       0001h - no 80386+ detected
  210.       0002h - system already in protected mode and no VCPI or DPMI found
  211.       0003h - DPMI - host is not 32bit
  212.     CF - set on error, if no error:
  213.       BX - number of paragraphs needed for protected mode data (may be 0)
  214.       CL - processor type:
  215.     03h - 80386
  216.     04h - 80486
  217.     05h - 80586
  218.     06h-FFh - reserved for future use
  219.       CH - protected mode type:
  220.     00h - raw
  221.     01h - XMS
  222.     02h - VCPI
  223.     03h - DPMI
  224.  
  225. ) _pm_init - Initialize protected mode:
  226.   In:
  227.     ES - real mode segment for protected mode data (ignored if not needed)
  228.   Out:
  229.     AX - return code:
  230.       0000h - successful
  231.       0001h - no 80386+ detected
  232.       0002h - system already in protected mode and no VCPI or DPMI found
  233.       0003h - DPMI - host is not 32bit
  234.       0004h - could not enable A20 gate
  235.       0005h - DPMI - could not enter 32bit protected mode
  236.       0006h - DPMI - could not allocate needed selectors
  237.     CF - set on error, if no error:
  238.       ESP - high word clear
  239.       CS - 16bit selector for real mode CS with limit of 64k
  240.       SS - 32bit selector for real mode SS with limit of 64k
  241.       DS - 32bit selector for real mode DS with limit of 64k
  242.       ES - 32bit selector for PSP with limit of 100h
  243.       FS - 0 (NULL selector)
  244.       GS - 0 (NULL selector)
  245.  
  246.   The CS, DS, and SS selectors returned from _pm_init can be modified or
  247. freed by your code. The PSP selector and the converted environment selector in
  248. the PSP may not be. To terminate under PMODE, your code must issue an INT 21h
  249. function 4ch in protected mode. Just like in real mode, AL is the return code.
  250. Your code should only terminate from the main stream of execution. That is, do
  251. not try to quit from a protected mode IRQ handler or a real mode callback.
  252. Before termination, your code has the following responsibilities:
  253.  
  254. ) Restore any real mode interrupt vectors which were hooked.
  255.  
  256. ) Free any extended memory blocks that were allocated (this is a departure
  257.   from the DPMI standard).
  258.  
  259. 1.1 - Segments, selectors, and descriptors:
  260. -------------------------------------------
  261.  
  262.   As you know (I hope), in protected mode, selectors are used in place of
  263. actual segment values in segment registers. Selectors are basically indexes
  264. into system tables which contain all the information about segments in
  265. descriptors. You can think of selectors as handles to segments. They are
  266. independent of the actual location and size of the segment in memory.
  267.  
  268.   Under PMODE, your code can allocate its own selectors and descriptors. You
  269. can set up code segments, data segments, and your own stack segments. These
  270. segments can be either 16bit, 32bit, or a mix. The best use of the flexibility
  271. of protected mode is to set up very large segments, in effect, eliminating the
  272. need for segmentation. You can set up a code descriptor, and set its size to
  273. 4G. Then a data descriptor of that same size and with the same base address.
  274. When all memory is addressable from a single segment, there is little need for
  275. other segments. But they are available, possibly for code modules to be loaded
  276. from disk into seperate segments.
  277.  
  278.   After allocating a descriptor, you code can set it up in one shot, with
  279. Set Descriptor function (000ch). Or you can set the base address, limit, and
  280. access rights/type seperately. You can also allocate a descriptor and have it
  281. automatically set to the same base address and size as another descriptor
  282. using the Create Alias Descriptor function (000ah). You code can also read a
  283. whole descriptor or base address of a descriptor. There is no Get Segment
  284. Limit function because the LSL instruction performs that function. The LAR
  285. instruction returns the access rights/type of a descriptor.
  286.  
  287.   Technically, it is possible for DPMI to deny requests to set up very large
  288. segments for protection reasons. But no DPMI host that I know of does this.
  289. They all do protection at the paging level. DPMI 1.0 specifies a function
  290. that returns an absolute ceiling for large segments. Allowing for flat memory,
  291. but falling short of the full 4G linear address range. I would not worry about
  292. this. If DPMI 1.0 hosts started to deny requests to set segment sizes to 4G,
  293. many protected mode extended programs would cease to function.
  294.  
  295.   When setting up a data descriptor which will be used as a stack segment, be
  296. aware that the B bit will determine whether PUSHes and POPs on that stack use
  297. SP or ESP as the top of stack pointer. However, even if you use a stack with
  298. the B bit clear (using SP), ESP should still be the top of stack pointer.
  299. Which means that when using a 16bit stack segment, the high word of ESP MUST
  300. be clear.
  301.  
  302. 1.2 - Stacks and mode switching:
  303. --------------------------------
  304.  
  305.   Within your main stream of execution, your code can set up its own stack.
  306. But there are times when a stack is provided to your code and your code should
  307. stay on that stack. At those times, your code may switch stacks during
  308. processing, but should return on the same stack it was called. This is during
  309. servicing of hardware interrupts or real mode callbacks in protected mode.
  310.  
  311.   Switching between protected mode and real mode can be accomplished in one of
  312. many ways. In protected mode, the default IRQ handlers switch to real mode to
  313. execute the real mode handler for the specific IRQ that was called. A software
  314. INT instruction in protected mode is also, by default, sent to on to real mode
  315. for processing. There are three specific functions which allow you to call
  316. real mode interrupts and procedures in a much more structured manner. There
  317. are real mode callbacks. These are basically addresses in real mode which,
  318. when called in real mode, transfer control to protected mode routines defined
  319. by your code. And finally, there is raw mode switching. Your code can obtain
  320. the addresses of a real mode routine which will switch the system into
  321. protected mode, and a protected mode routine which will switch the system into
  322. real mode. This is the lowest level, and quickest, method of switching modes.
  323. IRQ and INT redirection is discussed later, as are real mode callbacks.
  324.  
  325.   The INT 31h functions 0300h, 0301h, and 0302h allow your code to call real
  326. mode interrupts of FAR routines. Since protected mode selectors are not valid
  327. in real mode, your must pass the values to load into the segment registers in
  328. real mode, for the interrupt or routine, in a memory structure. This structure
  329. also contains the general registers as you want to pass them to real mode.
  330. Using these INT 31h functions, you can specify a portion of data from the
  331. protected mode stack to be put on the real mode stack for the interrupt or
  332. procedure call. You also do not have to provide a real mode stack. If you set
  333. the SS and SP fields in the register structure to 0, PMODE will provide a real
  334. mode stack for the real mode call. If you prefer, however, you can provide the
  335. stack yourself. Upon return from the real mode call, the register structure
  336. will contain the values that were passed back in the registers from the real
  337. mode interrupt handler or procedure. The CS, IP, SS, and SP fields will remain
  338. unmodified though.
  339.  
  340.   Using the raw mode switching routines is the fastest way to switch between
  341. modes. However, if these functions are to be used, special measures must be
  342. taken to preserve the state of the system. If using raw mode switching, you
  343. must use the state save/restore fuctions whose addresses you can obtain with
  344. INT 31h function 0305h. The state is saved in a buffer you provide. The stack
  345. is a good place for this buffer. Some example code is in order:
  346.  
  347. buffersize      dd      ?               ; size of state buffer
  348.  
  349. pmstate         df      ?               ; selector:offset of state routine
  350. pmtorm          df      ?               ; selector:offset of switch routine
  351.  
  352. rmstate         dd      ?               ; segment:offset of state routine
  353. rmtopm          dd      ?               ; segment:offset of switch routine
  354.  
  355. ; this code gets and stores the addresses of the various routines
  356.  
  357.         mov ax,305h                     ; get addresses of state save/restore
  358.         int 31h                         ;  routines
  359.  
  360.         movzx eax,ax                    ; zero high word of EAX
  361.         mov buffersize,eax              ; size of state buffer
  362.         mov word ptr rmstate[0],cx      ; offset of real mode state routine
  363.         mov word ptr rmstate[2],bx      ; segment of real mode state routine
  364.         mov dword ptr pmstate[0],edi    ; offset of protected mode routine
  365.         mov word ptr pmstate[4],si      ; selector of protected mode routine
  366.  
  367.         mov ax,306h                     ; get addresses of mode switch
  368.         int 31h                         ;  routines
  369.  
  370.         mov word ptr rmtopm[0],cx       ; offset of real mode switch routine
  371.         mov word ptr rmtopm[2],bx       ; segment of real mode switch routine
  372.         mov dword ptr pmtorm[0],edi     ; offset of protected mode routine
  373.         mov word ptr pmtorm[4],si       ; selector of protected mode routine
  374.  
  375. ; this code saves the state and jumps to real mode
  376.  
  377.         sub esp,buffersize              ; allocate buffer space on stack
  378.         mov edi,esp                     ; set ES:EDI = SS:ESP, buffer address
  379.         mov ax,ss
  380.         mov es,ax
  381.         xor al,al                       ; set AL = 0, save state
  382.         call pmstate                    ; save state
  383.  
  384.         mov ax,real_mode_DS_value       ; set values for real mode registers
  385.         mov cx,real_mode_ES_value
  386.         mov dx,real_mode_SS_value
  387.         mov bx,real_mode_SP_value
  388.         mov si,real_mode_CS_value
  389.         mov di,real_mode_IP_value
  390.         jmp pmtorm                      ; switch to real mode
  391.  
  392. ; this would restore the state after a return from real mode
  393.  
  394.         mov edi,esp                     ; set ES:EDI = SS:ESP, buffer address
  395.         mov ax,ss
  396.         mov es,ax
  397.         mov al,1                        ; set AL = 1, restore state
  398.         call pmstate                    ; restore state
  399.         add esp,buffersize              ; discard stack buffer space
  400.  
  401.   Real mode code to save/restore the state and call protected mode would be
  402. similar, except that EBX would be used to pass a value for ESP, and EDI would
  403. be used to pass EIP rather than IP in switching modes. Also, ES:DI would be
  404. used as the state buffer rather than ES:EDI.
  405.  
  406. 1.3 - Interrupts:
  407. -----------------
  408.  
  409.   When protected mode is first entered, all interrupts except those providing
  410. DPMI functionality are directed to a handler which will pass them on to real
  411. mode. That is, a software INT instruction executed by your code in protected
  412. mode will cause the CPU to be switched to real mode and the interrupt will be
  413. re-issued in real mode. After the interrupt handler returns, the system will
  414. be switched back to protected mode. All general registers (EAX, EBX, ECX, EDX,
  415. ESI, EDI, and EBP) in protected mode are passed on to the real mode handler,
  416. and the general registers and flags are passed back from real mode. The
  417. segment registers are not passed on to real mode since segment registers have
  418. different meanings in protected mode and real mode. This means that you can
  419. call simple interrupt routines which do not require values in segment
  420. registers, such as the keyboard BIOS function 0 to read a character from the
  421. keyboard, by just setting AH to 0 and issuing an INT 16h in protected mode. If
  422. you need to pass segment registers to a real mode interrupt handler, you must
  423. use the INT 31h function 0300h.
  424.  
  425.   IRQs are likewise passed on to real mode. PMODE will not, for the sake of a
  426. little speed increase, pass any registers to or from a real mode IRQ handler.
  427. A real DPMI host probably will pass the general registers just as it would for
  428. a software INT instruction. You may hook a protected mode interrupt vector for
  429. any interrupt, 0-0ffh, and process the interrupt entirely in protected mode if
  430. you wish. Or you can do some processing in protected mode, then chain to the
  431. real mode handler by passing control to the previous handler for the interrupt
  432. your code hooked.
  433.  
  434.   If an IRQ occurs in real mode, by default, it will not be passed on to its
  435. protected mode handler. Rather, it will go directly to its real mode handler.
  436. Under a real DPMI host, the IRQ will probably be sent on to its protected mode
  437. handler first. If you wish send IRQs that occur in real mode to a protected
  438. mode handler, set up a real mode callback for that interrupt vector. Or faster
  439. than that, install your own real mode routine which will switch to your
  440. protected mode code using the raw mode switching routines.
  441.  
  442.   PMODE will provide a real mode stack for both the software INT redirection
  443. and the hardware IRQ redirection to real mode. If a real mode stack is
  444. unavailable because of too many nested calls to real mode, the PC speaker will
  445. be turned on and the machine will be hung. I prefer this to clunky exception
  446. code messing up my nice and pretty extender.
  447.  
  448.   In protected mode, when interrupt handlers are called, the interrupt flag is
  449. not disabled like it is in real mode. This is done only for IRQs and
  450. interrupts 0-7. Handlers for all other interrupts in protected mode must not
  451. assume the interrupt flag has been cleared for them. If they need interrupts
  452. disabled, they must do it themselves.
  453.  
  454.   Under DPMI, the interrupt flag may need to be virtualized. I will spare you
  455. a long explanation because any good DPMI text will give that to you. But I
  456. will give you some rules:
  457.  
  458. ) You must not assume anything about instructions that would normally affect
  459.   the interrupt flag. Instructions like POPF and IRETD may have no effect on
  460.   the current status of the interrupt flag. Also, PUSHF or an INT may not
  461.   store the interrupt flag correctly, so do not trust them to get information
  462.   on the interrupt flag.
  463.  
  464. ) The only things you can be sure will affect the interrupt flag are CLI, STI,
  465.   and INT 31h functions 0900h and 0901h.
  466.  
  467. ) If you need to learn the current status of the interrupt flag, you must use
  468.   one of the INT 31h functions, 0900h to clear and get the status of the
  469.   interrupt flag, 0901h to set and get the status of the flag, or 0902h which
  470.   simply returns the current value of the interrupt flag.
  471.  
  472. ) Since IRETD may not affect the interrupt flag, you should re-enable
  473.   interrupts in a protected mode IRQ handler. This is because the interrupt
  474.   flag will have been cleared upon entry to the handler.
  475.  
  476.   When writing interrupt handlers, you must terminate them with an IRETD, not
  477. a simple IRET. For hardware IRQ handlers, you may want to make sure that any
  478. code and data that may be touched by the IRQ handler resides in low memory,
  479. below 1M. This memory is locked under DPMI, and will prevent having to swap
  480. from disk at interrupt time under DPMI hosts which support virtual memory. One
  481. other thing you should remember about IRQ handlers. IRQ 2 is really IRQ 9.
  482. Devices which say they use IRQ 2 are actually using IRQ 9. In real mode, the
  483. BIOS handler for IRQ 9 redirects it to the handler for IRQ 2. There is no such
  484. redirection done in protected mode. So if you wish to write a handler for
  485. IRQ 2 in protected mode, you must put it on IRQ 9. And remember to send the
  486. EOI to the second interrupt controller. The BIOS IRQ 9 handler does that, but
  487. you don't have the BIOS anymore.
  488.  
  489. 1.4 - Real mode callbacks:
  490. --------------------------
  491.  
  492.   Real mode callbacks allow code running in real mode to call protected mode
  493. procedures in a transparent manner. The real mode code thinks it is passing
  494. control to another real mode procedure. This is, in reality, a real mode
  495. callback. Which is basically a small routine which stores the values of the
  496. real mode registers in a structure, then switches to protected mode and passes
  497. control to a protected mode routine you specify.
  498.  
  499.   Callbacks are allocated and freed just like descriptors or memory. When
  500. allocating a callback, your code specifies the address of the protected mode
  501. routine that is to gain control when the real mode callback is called. You
  502. must also specify the selector:offset of a memory structure that is to recieve
  503. the contents of the registers in real mode. The format of this structure is
  504. the same as for INT 31h functions 0300h, 0301h, and 0302h. When the protected
  505. mode routine for a real mode callback gets control, interrupts will be
  506. disabled, and the following registers are defined:
  507.  
  508.   DS:ESI - selector:offset corresponding to real mode SS:SP
  509.   ES:EDI - selector:offset of real mode register data structure
  510.   SS:ESP - protecterd mode stack provided by PMODE or the DPMI host
  511.  
  512. The real mode register data structure has the following format:
  513.  
  514.   Offset  Length  Contents
  515.   00h     4       EDI
  516.   04h     4       ESI
  517.   08h     4       EBP
  518.   0ch     4       reserved, ignored
  519.   10h     4       EBX
  520.   14h     4       EDX
  521.   18h     4       ECX
  522.   1ch     4       EAX
  523.   20h     2       CPU status flags
  524.   22h     2       ES
  525.   24h     2       DS
  526.   26h     2       FS
  527.   28h     2       GS
  528.   2ah     2       IP, undefined
  529.   2ch     2       CS, undefined
  530.   2eh     2       SP
  531.   30h     2       SS
  532.  
  533.   All fields except the CS and IP are filled in with the contents of the real
  534. mode registers when the real mode callback got control. The protected mode
  535. callback procedure can extract its parameters from the register data structure
  536. and/or the real mode stack. Remember that the segment registers contain real
  537. mode segment addresses, not protected mode selectors.
  538.  
  539.   The protected mode callback procedure exits with an IRETD with the address
  540. of the real mode register data structure in ES:EDI. Information can be passed
  541. back to real mode by modifying the contents of the register data structure and
  542. the real mode stack. The protected mode callback routine is responsible for
  543. setting the correct address for the resumption of execution in real mode in
  544. the CS:IP fields of the register data structure. It is also responsible for
  545. updating the SS:SP fields in the register data structure to remove the address
  546. of the calling real mode routine from the real mode stack.
  547.  
  548.   The real mode register data structure and the DS selector used to map the
  549. real mode SS segment are static. This is not a problem if you leave interrupts
  550. disabled throughout the protected mode callback routine. But if you intend to
  551. re-enable interrupts, you must make sure you do not use the DS selector
  552. anymore. If you need to access the real mode stack after enabling interrupts,
  553. you must create an alias descriptor for the DS selector passed to your
  554. callback procedure. Or you can take other measures, but just remember that the
  555. original DS selector is no longer safe after enabling interrupts in a
  556. protected mode callback routine.
  557.  
  558.   Since the real mode register data structure is also static, you should take
  559. special care if you wish to enable interrupts in a callback. Since the data
  560. structure is needed for the exit from the callback, you can not simply
  561. discard it. You should make a copy of the data structure. You can then pass
  562. back the copy when you exit the callback procedure. The ES:EDI upon exit is
  563. not required to be the same as on entry.
  564.  
  565. 1.5 - PMODE specifics:
  566. ----------------------
  567.  
  568.   PMODE makes several variables public. These control certain things when
  569. running under VCPI, XMS, or a raw system. Under DPMI, these variables do
  570. absolutely nothing. The size of the low memory protected mode buffer required
  571. for _pm_init is directly affected by these variables. Thus, they must be set
  572. to the same values for the call to _pm_info and _pm_init. You should only
  573. modify these variables before switching into protected mode.
  574.  
  575. ) _pm_pagetables - This specifies the number of page tables you want to have
  576.   under VCPI. Each page table requires 4k and maps 4M of linear memory. Page
  577.   tables only define linear address space, not actual physical memory. The
  578.   amount of extended memory that will be available to your code will be the
  579.   lesser of linear and physical memory in the system. Setting a higher number
  580.   of page tables will not give you any more physical memory than is available
  581.   in the system, but it will give you more linear address space where physical
  582.   memory can be mapped. This helps reduce fragmentation of memory when
  583.   allocating extended memory blocks under VCPI. Never set this variable to 0,
  584.   since the first page table maps the low megabyte of real mode memory.
  585.  
  586. ) _pm_selectors - This is the total number of descriptors you want PMODE to
  587.   make available to your code for allocation. The range for this variable is
  588.   0 to about 8150. The actual max number of descriptors that can exist in the
  589.   global descriptor table, which is where descriptors under PMODE reside, is
  590.   8191. But some of these descriptors are used by PMODE. Also, DPMI may not
  591.   be able to provide quite as many as 8000 descriptors. Each descriptor takes
  592.   up 8 bytes of space in the low memory protected mode buffer.
  593.  
  594. ) _pm_callbacks - This is the number of real mode callbacks you want PMODE to
  595.   provide for allocation. Each callback takes up 25 bytes of space. You may
  596.   set this variable to 0.
  597.  
  598. ) _pm_rmstacklen - This is the size of the real mode stack, in paragraphs,
  599.   that is provided for IRQ and INT redirection to real mode. Also for INT 31h
  600.   functions 0300h, 0301h, and 0302h when the SS:SP field in the register
  601.   structure is zero.
  602.  
  603. ) _pm_rmstacks - This is the number of real mode stacks you want present in
  604.   case of nested calls to real mode. There must be at least one.
  605.  
  606. ) _pm_pmstacklen - This is the size of the protected mode stack, in
  607.   paragraphs, to provide for protected mode procedures which handle real mode
  608.   callbacks.
  609.  
  610. ) _pm_pmstacks - This is the number of protected mode stacks you want present
  611.   in case of nested callbacks. If your code is not going to be using real mode
  612.   callbacks, you may set this variable, along with _pm_pmstacklen and
  613.   _pm_callbacks, to zero.
  614.  
  615. ) _pm_mode - This is a general purpose flag variable for PMODE. Currently only
  616.   bit 0 has a meaning, all the other bits should be clear. Bit 0 determines
  617.   the order of detection of DPMI and VCPI. If bit 0 is clear (default), PMODE
  618.   will check for DPMI first. If bit 0 is set, VCPI will be checked first. This
  619.   only means that in systems that provide both VCPI and DPMI, you will be able
  620.   to run under VCPI instead of DPMI if you choose. This means that your code
  621.   will run faster, and may avoid bugs present in the DPMI implementation of
  622.   the memory manager in place. If you choose to detect VCPI first, and it is
  623.   not present but DPMI is (like in Windows or OS/2), then DPMI will be used
  624.   anyway.
  625.  
  626. 1.6 - PMODE internal stacks:
  627. ----------------------------
  628.  
  629.   The memory space of the real mode and protected mode stacks used by PMODE
  630. for INT and IRQ redirection and callbacks can be used by your code if you do
  631. your own raw mode switching and need stack space. This is just a minor memory
  632. optimization, especially useful if you will have many nested mode switches
  633. using PMODE and raw mode services. These memory areas are only available under
  634. a VCPI/XMS/raw system. If a DPMI host is already in place, PMODE is not in
  635. control and does not have these memory areas to share with your code, in which
  636. case you will have to allocate any stack buffers you need yourself anyway.
  637.  
  638.   All of PMODE except this is the standard DPMI interface. If you use this
  639. technique I can not guarantee support in future major revisions of PMODE, nor
  640. can you be sure of 'portability' to other extenders. On the other hand, if you
  641. use this method, you will have to handle setting up your own stack buffers
  642. anyway if the system is running under a DPMI host. This will make your code
  643. 'portable' since, if ever you move it, you have the stack buffer code right
  644. there. The reason I make this option available in PMODE, is that for a while
  645. now, multiple nested stack areas for PMODE and any external shell for it have
  646. bothered me as an unnecessary waste of memory.
  647.  
  648.   The memory areas of the stacks are defined by four variables made public in
  649. the PMODE segment. They define the base and current top of the entire real
  650. mode and protected mode stack areas (all nested stacks for each mode). The
  651. protected mode base and top are dword pointers relative to the beginning of
  652. memory (0000:0000). The real mode base and top are real mode segment word
  653. values. The tops of the stacks are all that you really need to use the stack
  654. areas, the bases are provided in case you want to check for running out of
  655. nested stacks. The four variables are as follows:
  656.  
  657. ) pmstacktop - This is the linear address of the current top of the protected
  658.   mode stack area.
  659.  
  660. ) pmstackbase - This is the linear base address of the entire protected mode
  661.   stack area. If ever the value of pmstacktop drops below this value, you ran
  662.   out of memory in the protected mode stack buffer.
  663.  
  664. ) rmstacktop - This is the real mode segment value of the current top of the
  665.   real mode stack area.
  666.  
  667. ) rmstackbase - This is the real mode segment value of the base of the real
  668.   mode stack area. Again, if the value of rmstacktop falls below this value,
  669.   you are out of real mode stack buffer memory. This does not necessarily mean
  670.   death, since you would be accessing this before you actually switch to real
  671.   mode, it simply means there is not enough room in the PMODE stack buffers
  672.   to switch to real mode.
  673.  
  674.   The size of the entire real and protected mode stack areas is defined when
  675. you enter protected mode by the variables _pm_rmstacklen, _pm_rmstacks,
  676. _pm_pmstacklen, _pm_pmstacks. The real mode stack area is the one used by
  677. PMODE for INT and IRQ redirection, and INT 31h functions 0300h, 0301h, and
  678. 0302h, and its entire size in bytes is _pm_rmstacklen * _pm_rmstacks * 16. The
  679. protected mode stack area is the one used by callbacks and its size is
  680. _pm_pmstacklen * _pm_pmstacks * 16. This means that if you intend to use the
  681. PMODE protected mode stacks, you must make them available through
  682. _pm_pmstacklen and _pm_pmstacks even if you do not use real mode callbacks.
  683. These stack areas are used from the top to bottom as nested mode stacks are
  684. allocated.
  685.  
  686. An example of use:
  687.  
  688. ; this code loads DX:BX with a valid real mode SS:SP for a raw mode switch
  689. ; to real mode assuming DS is a selector mapping the PMODE segment PMODE_TEXT
  690.  
  691.         mov dx,rmstacktop               ; DX = current real mode stack top
  692.         mov bx,_pm_rmstacklen           ; BX = length of PMODE real mode stack
  693.         sub dx,bx                       ; subtract size of stack from top
  694.  
  695.         cmp dx,rmstackbase              ; check if ran out of memory
  696.         jb ran_out_of_RM_stack_memory
  697.  
  698.         mov rmstacktop,dx               ; put the adjusted value back
  699.         shl bx,4                        ; adjust stack len from para to bytes
  700.  
  701. ; DX:BX now contains the real mode segment:offset of a valid real mode stack
  702. ; as could be used by the raw mode switching services, after the return from
  703. ; real mode you must remember to adjust the current stack top
  704.  
  705.         mov ax,_pm_rmstacklen           ; AX = length of real mode stack
  706.         add rmstacktop,ax               ; readjust real mode stack top
  707.  
  708. ; this code loads DX:EBX with a valid protected mode SS:ESP for a raw mode
  709. ; switch to protected mode assuming DS is PMODE_TEXT
  710.  
  711.         mov ebx,pmstacktop              ; EBX = current protected stack top
  712.         mov ecx,ebx                     ; ECX = EBX for adjust
  713.         mov eax,_pm_pmstacklen          ; EAX = length of protected mode stack
  714.         shl eax,4                       ; convert length from para to bytes
  715.         sub ecx,eax                     ; subtract size of stack from top
  716.  
  717.         cmp ecx,pmstackbase             ; check if ran out of memory
  718.         jb ran_out_of_PM_stack_memory
  719.  
  720.         mov pmstacktop,ecx              ; put the adjusted value back
  721.  
  722. ; EBX now contains the top of a valid protected mode stack area relative to
  723. ; the beginning of memory, you must still load up DX with a valid protected
  724. ; mode SS and adjust EBX by the base address of that selector to convert it
  725. ; to a valid ESP relative to the base of the stack segment
  726.  
  727.         mov dx,PM_stack_selector        ; DX = SS selector for protected mode
  728.         sub ebx,PM_stack_selector_base  ; adjust EBX for a valid ESP
  729.  
  730. ; and ofcourse after the return from protected mode readjust the stack top
  731.  
  732.         mov eax,_pm_pmstacklen          ; EAX = length of protected mode stack
  733.         shl eax,4                       ; convert length from para to bytes
  734.         add pmstacktop,eax              ; readjust protected mode stack top
  735.  
  736.   You do not have to use _pm_rmstacklen and _pm_pmstacklen for the size of the
  737. stacks you allocate from the stack memory, but you should keep the sizes at
  738. least a dword multiple. Also do not make the stacks too small, at least 128
  739. bytes is a good minimum value.
  740.  
  741.   As I said, under a real DPMI host, PMODE does not initialize these stack
  742. memory areas. Your code would have to do it on its own. But you can use the
  743. same variables to store the base and top of the stack memory areas your code
  744. allocates since PMODE will not be using them as it will not be in control.
  745. This means you can use the same code for raw mode switching and mode stack
  746. allocation. All that will be required is some code at protected mode init time
  747. that will allocate some memory for the stack areas and store their base and
  748. top in the respective variables.
  749.  
  750. ------------------------------------------------------------------------------
  751. 2 - Functions:
  752. --------------
  753.  
  754.   PMODE duplicates a subset of DPMI protected mode functions. These functions
  755. are available ONLY in protected through INT 31h. They provide descriptor
  756. services, extended memory services, interrupt services, translation services,
  757. and some other misc things. A function is called by setting AX to the function
  758. code, setting any other registers for the function, and executing an INT 31h.
  759. Upon return, the carry flag will be clear if the function was successful. If
  760. the carry flag is set, the function failed. In this case, an error code will
  761. be placed in AX. However, DPMI 0.9 will not return error codes, just the carry
  762. flag set on errors. All other registers are preserved unless otherwise stated.
  763.  
  764. 2.0 - Function 0000h - Allocate Descriptors:
  765. --------------------------------------------
  766.  
  767. Allocates one or more descriptors in the client's descriptor table. The
  768. descriptor(s) allocated must be initialized by the application with other
  769. function calls.
  770.  
  771. In:
  772.   AX     = 0000h
  773.   CX     = number of descriptors to allocate
  774.  
  775. Out:
  776.   if successful:
  777.   AX     = base selector
  778.  
  779.   if failed:
  780.   AX     = error code:
  781.            8011h - descriptor unavailable
  782.            8021h - invalid value (CX = 0) (VCPI/XMS/raw only)
  783.  
  784. Notes:
  785. ) If more that one descriptor was requested, the function returns a base
  786.   selector referencing the first of a contiguous array of descriptors. The
  787.   selector values for subsequent descriptors in the array can be calculated
  788.   by adding the value returned by INT 31h function 0003h.
  789.  
  790. ) The allocated descriptor(s) will be set to expand-up writeable data, with
  791.   the present bit set and a base and limit of zero. The privilege level of the
  792.   descriptor(s) will match the client's code segment privilege level.
  793.  
  794. 2.1 - Function 0001h - Free Descriptor:
  795. ---------------------------------------
  796.  
  797. Frees a descriptor.
  798.  
  799. In:
  800.   AX     = 0001h
  801.   BX     = selector for the descriptor to free
  802.  
  803. Out:
  804.   if failed:
  805.   AX     = error code:
  806.            8022h - invalid selector
  807.  
  808. Notes:
  809. ) Each descriptor allocated with INT 31h function 0000h must be freed
  810.   individually with the function. Even if it was previously allocated as part
  811.   of a contiguous array of descriptors.
  812.  
  813. ) Under DPMI 1.0/VCPI/XMS/raw, any segment registers which contain the
  814.   selector being freed are zeroed by this function.
  815.  
  816. 2.2 - Function 0003h - Get Selector Increment Value:
  817. ----------------------------------------------------
  818.  
  819. The Allocate Descriptors function (0000h) can allocate an array of contiguous
  820. descriptors, but only return a selector for the first descriptor. The value
  821. returned by this function can be used to calculate the selectors for
  822. subsequent descriptors in the array.
  823.  
  824. In:
  825.   AX     = 0003h
  826.  
  827. Out:
  828.   always successful:
  829.   AX     = selector increment value
  830.  
  831. Notes:
  832. ) The increment value is always a power of two.
  833.  
  834. 2.3 - Function 0006h - Get Segment Base Address:
  835. ------------------------------------------------
  836.  
  837. Returns the 32bit linear base address from the descriptor table for the
  838. specified segment.
  839.  
  840. In:
  841.   AX     = 0006h
  842.   BX     = selector
  843.  
  844. Out:
  845.   if successful:
  846.   CX:DX  = 32bit linear base address of segment
  847.  
  848.   if failed:
  849.   AX     = error code:
  850.            8022h - invalid selector
  851.  
  852. Notes:
  853. ) Client programs must use the LSL instruction to query the limit for a
  854.   descriptor.
  855.  
  856. 2.4 - Function 0007h - Set Segment Base Address:
  857. ------------------------------------------------
  858.  
  859. Sets the 32bit linear base address field in the descriptor for the specified
  860. segment.
  861.  
  862. In:
  863.   AX     = 0007h
  864.   BX     = selector
  865.   CX:DX  = 32bit linear base address of segment
  866.  
  867. Out:
  868.   if failed:
  869.   AX     = error code:
  870.            8022h - invalid selector
  871.            8025h - invalid linear address (changing the base would cause the
  872.                    descriptor to reference a linear address range outside that
  873.                    allowed for DPMI clients) (DPMI 1.0 only)
  874.  
  875. Notes:
  876. ) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains the
  877.   selector specified in register BX will be reloaded. DPMI 0.9 may do this,
  878.   but it is not guaranteed.
  879.  
  880. ) I hope you have enough sense not to try to modify your current CS or SS
  881.   descriptor.
  882.  
  883. 2.5 - Function 0008h - Set Segment Limit:
  884. -----------------------------------------
  885.  
  886. Sets the limit field in the descriptor for the specified segment.
  887.  
  888. In:
  889.   AX     = 0008h
  890.   BX     = selector
  891.   CX:DX  = 32bit segment limit
  892.  
  893. Out:
  894.   if failed:
  895.   AX     = error code:
  896.            8021h - invalid value (the limit is > 1M, but the low 12 bits are
  897.                    not set)
  898.            8022h - invalid selector
  899.            8025h - invalid linear address (changing the base would cause the
  900.                    descriptor to reference a linear address range outside that
  901.                    allowed for DPMI clients) (DPMI 1.0 only)
  902.  
  903. Notes:
  904. ) The value supplied to the function in CX:DX is the byte length of the
  905.   segment-1.
  906.  
  907. ) Segment limits greater than or equal to 1M must be page aligned. That is,
  908.   they must have the low 12 bits set.
  909.  
  910. ) This function has an implicit effect on the "G" bit in the segment's
  911.   descriptor.
  912.  
  913. ) Client programs must use the LSL instruction to query the limit for a
  914.   descriptor.
  915.  
  916. ) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains the
  917.   selector specified in register BX will be reloaded. DPMI 0.9 may do this,
  918.   but it is not guaranteed.
  919.  
  920. ) I hope you have enough sense not to try to modify your current CS or SS
  921.   descriptor.
  922.  
  923. 2.6 - Function 0009h - Set Descriptor Access Rights:
  924. ----------------------------------------------------
  925.  
  926. Modifies the access rights field in the descriptor for the specified segment.
  927.  
  928. In:
  929.   AX     = 0009h
  930.   BX     = selector
  931.   CX     = access rights/type word
  932.  
  933. Out:
  934.   if failed:
  935.   AX     = error code:
  936.            8021h - invalid value (access rights/type word invalid)
  937.            8022h - invalid selector
  938.            8025h - invalid linear address (changing the base would cause the
  939.                    descriptor to reference a linear address range outside that
  940.                    allowed for DPMI clients) (DPMI 1.0 only)
  941.  
  942. Notes:
  943. ) The access rights/type word passed to the function in CX has the following
  944.   format:
  945.  
  946.     Bit: 15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
  947.        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  948.        | G |B/D| 0 | ? |       ?       | 1 |  DPL  | 1 |C/D|E/C|W/R| A |
  949.        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  950.  
  951.     G   - 0=byte granular, 1=page granular
  952.     B/D - 0=default 16bit, 1=default 32bit
  953.     DPL - must be equal to caller's CPL
  954.     C/D - 0=data, 1=code
  955.     E/C - data: 0=expand-up, 1=expand-down
  956.           code: must be 0 (non-conforming)
  957.     W/R - data: 0=read, 1=read/write
  958.           code: must be 1 (readable)
  959.     A   - 0=not accessed, 1=accessed
  960.     0   - must be 0
  961.     1   - must be 1
  962.     ?   - ignored
  963.  
  964. ) Client programs should use the LAR instruction to examine the access rights
  965.   of a descriptor.
  966.  
  967. ) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains the
  968.   selector specified in register BX will be reloaded. DPMI 0.9 may do this,
  969.   but it is not guaranteed.
  970.  
  971. ) I hope you have enough sense not to try to modify your current CS or SS
  972.   descriptor.
  973.  
  974. 2.7 - Function 000Ah - Create Alias Descriptor:
  975. -----------------------------------------------
  976.  
  977. Creates a new data descriptor that has the same base and limit as the
  978. specified descriptor.
  979.  
  980. In:
  981.   AX     = 000ah
  982.   BX     = selector
  983.  
  984. Out:
  985.   if successful:
  986.   AX     = data selector (alias)
  987.  
  988.   if failed:
  989.   AX     = error code:
  990.            8011h - descriptor unavailable
  991.            8022h - invalid selector
  992.  
  993. Notes:
  994. ) The selector supplied to the function may be either a data descriptor or
  995.   a code descriptor. The alias descriptor created is always an expand-up
  996.   writeable data segment.
  997.  
  998. ) The descriptor alias returned by this function will not track changes to the
  999.   original descriptor.
  1000.  
  1001. 2.8 - Function 000Bh - Get Descriptor:
  1002. --------------------------------------
  1003.  
  1004. Copies the descriptor table entry for the specified selector into an 8 byte
  1005. buffer.
  1006.  
  1007. In:
  1008.   AX     = 000bh
  1009.   BX     = selector
  1010.   ES:EDI = selector:offset of 8 byte buffer
  1011.  
  1012. Out:
  1013.   if successful:
  1014.   buffer pointed to by ES:EDI contains descriptor
  1015.  
  1016.   if failed:
  1017.   AX     = error code:
  1018.            8022h - invalid selector
  1019.  
  1020. 2.9 - Function 000Ch - Set Descriptor:
  1021. --------------------------------------
  1022.  
  1023. Copies the contents of an 8 byte buffer into the descriptor for the specified
  1024. selector.
  1025.  
  1026. In:
  1027.   AX     = 000ch
  1028.   BX     = selector
  1029.   ES:EDI = selector:offset of 8 byte buffer containing descriptor
  1030.  
  1031. Out:
  1032.   if failed:
  1033.   AX     = error code:
  1034.            8021h - invalid value (access rights/type word invalid)
  1035.            8022h - invalid selector
  1036.            8025h - invalid linear address (changing the base would cause the
  1037.                    descriptor to reference a linear address range outside that
  1038.                    allowed for DPMI clients) (DPMI 1.0 only)
  1039.  
  1040. ) The descriptors access rights/type word at offset 5 within the descriptor
  1041.   follows the same format and restrictions as the access rights/type parameter
  1042.   CX to the Set Descriptor Access Rights function (0009h).
  1043.  
  1044. ) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains the
  1045.   selector specified in register BX will be reloaded. DPMI 0.9 may do this,
  1046.   but it is not guaranteed.
  1047.  
  1048. ) I hope you have enough sense not to try to modify your current CS or SS
  1049.   descriptor or the descriptor of the buffer.
  1050.  
  1051. 2.10 - Function 000Eh - Get Multiple Descriptors:
  1052. -------------------------------------------------
  1053.  
  1054. Copies one or more descriptor table entries into a buffer.
  1055.  
  1056. In:
  1057.   AX     = 000eh
  1058.   CX     = number of descriptors to copy
  1059.   ES:EDI = selector:offset of a buffer in the following format:
  1060.  
  1061.            Offset  Length  Contents
  1062.            00h     2       Selector #1 (set by client)
  1063.            02h     8       Descriptor #1 (returned by host)
  1064.            0ah     2       Selector #2 (set by client)
  1065.            0ch     8       Descriptor #2 (returned by host)
  1066.            ...     ...     ...
  1067.  
  1068. Out:
  1069.   if successful:
  1070.   buffer contains copies of the descriptors for the specified selectors
  1071.  
  1072.   if failed:
  1073.   AX     = error code:
  1074.            8022h - invalid selector
  1075.   CX     = number of descriptors successfully copied
  1076.  
  1077. Notes:
  1078. ) If an error occurs because of an invalid selector or descriptor, the
  1079.   function returns the number of descriptors which were successfully copied
  1080.   in CX. All of the descriptors which were copied prior to the one that failed
  1081.   are valid.
  1082.  
  1083. ) This function is not present under DPMI 0.9.
  1084.  
  1085. 2.11 - Function 000Fh - Set Multiple Descriptors:
  1086. -------------------------------------------------
  1087.  
  1088. Copies one or more descriptors from a client buffer into the descriptor table.
  1089.  
  1090. In:
  1091.   AX     = 000fh
  1092.   CX     = number of descriptors to copy
  1093.   ES:EDI = selector:offset of a buffer in the following format:
  1094.  
  1095.            Offset  Length  Contents
  1096.            00h     2       Selector #1
  1097.            02h     8       Descriptor #1
  1098.            0ah     2       Selector #2
  1099.            0ch     8       Descriptor #2
  1100.            ...     ...     ...
  1101.  
  1102. Out:
  1103.   if failed:
  1104.   AX     = error code:
  1105.            8021h - invalid value (access rights/type word invalid)
  1106.            8022h - invalid selector
  1107.            8025h - invalid linear address (changing the base would cause the
  1108.                    descriptor to reference a linear address range outside that
  1109.                    allowed for DPMI clients) (DPMI 1.0 only)
  1110.   CX     = number of descriptors successfully copied
  1111.  
  1112. Notes:
  1113. ) If an error occurs because of an invalid selector or descriptor, the
  1114.   function returns the number of descriptors which were successfully copied in
  1115.   CX. All of the descriptors which were copied prior to the one that failed
  1116.   are valid.
  1117.  
  1118. ) The descriptors access rights/type word at offset 5 within the descriptor
  1119.   follows the same format and restrictions as the access rights/type parameter
  1120.   CX to the Set Descriptor Access Rights (0009h) function.
  1121.  
  1122. ) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains a selector
  1123.   specified in the data structure will be reloaded. DPMI 0.9 may do this,
  1124.   but it is not guaranteed.
  1125.  
  1126. ) I hope you have enough sense not to try to modify your current CS or SS
  1127.   descriptor or the descriptor of the buffer.
  1128.  
  1129. ) This function is not present under DPMI 0.9.
  1130.  
  1131. 2.12 - Function 0200h - Get Real Mode Interrupt Vector:
  1132. -------------------------------------------------------
  1133.  
  1134. Returns the real mode segment:offset for the specified interrupt vector.
  1135.  
  1136. In:
  1137.   AX     = 0200h
  1138.   BL     = interrupt number
  1139.  
  1140. Out:
  1141.   always successful:
  1142.   CX:DX  = segment:offset of real mode interrupt handler
  1143.  
  1144. Notes:
  1145. ) The value returned in CX is a real mode segment address, not a protected
  1146.   mode selector.
  1147.  
  1148. 2.13 - Function 0201h - Set Real Mode Interrupt Vector:
  1149. -------------------------------------------------------
  1150.  
  1151. Sets the real mode segment:offset for the specified interrupt vector.
  1152.  
  1153. In:
  1154.   AX     = 0201h
  1155.   BL     = interrupt number
  1156.   CX:DX  = segment:offset of real mode interrupt handler
  1157.  
  1158. Notes:
  1159. ) The value passed in CX must be a real mode segment address, not a protected
  1160.   mode selector. Consequently, the interrupt handler must either reside in
  1161.   DOS memory (below the 1M boundary) or the client must allocate a real mode
  1162.   callback address.
  1163.  
  1164. 2.14 - Function 0204h - Get Protected Mode Interrupt Vector:
  1165. ------------------------------------------------------------
  1166.  
  1167. Returns the address of the current protected mode interrupt handler for the
  1168. specified interrupt.
  1169.  
  1170. In:
  1171.   AX     = 0204h
  1172.   BL     = interrupt number
  1173.  
  1174. Out:
  1175.   always successful:
  1176.   CX:EDX = selector:offset of protected mode interrupt handler
  1177.  
  1178. Notes:
  1179. ) The value returned in CX is a valid protected mode selector, not a real mode
  1180.   segment address.
  1181.  
  1182. 2.15 - Function 0205h - Set Protected Mode Interrupt Vector:
  1183. ------------------------------------------------------------
  1184.  
  1185. Sets the address of the protected mode interrupt handler for the specified
  1186. interrupt.
  1187.  
  1188. In:
  1189.   AX     = 0205h
  1190.   BL     = interrupt number
  1191.   CX:EDX = selector offset of protected mode interrupt handler
  1192.  
  1193. Out:
  1194.   if failed:
  1195.   AX     = error code:
  1196.            8022h - invalid selector
  1197.  
  1198. Notes:
  1199. ) The value passed in CX must be a valid protected mode selector, not a real
  1200.   mode segment address.
  1201.  
  1202. 2.16 - Function 0300h - Simulate Real Mode Interrupt:
  1203. -----------------------------------------------------
  1204.  
  1205. Simulates an interrupt in real mode. The function transfers control to the
  1206. address specified by the real mode interrupt vector. The real mode handler
  1207. must return by executing an IRET.
  1208.  
  1209. In:
  1210.   AX     = 0300h
  1211.   BL     = interrupt number
  1212.   BH     = must be 0
  1213.   CX     = number of words to copy from the protected mode stack to the real
  1214.            mode stack
  1215.   ES:EDI = selector:offset of real mode register data structure in the
  1216.            following format:
  1217.  
  1218.            Offset  Length  Contents
  1219.            00h     4       EDI
  1220.            04h     4       ESI
  1221.            08h     4       EBP
  1222.            0ch     4       reserved, ignored
  1223.            10h     4       EBX
  1224.            14h     4       EDX
  1225.            18h     4       ECX
  1226.            1ch     4       EAX
  1227.            20h     2       CPU status flags
  1228.            22h     2       ES
  1229.            24h     2       DS
  1230.            26h     2       FS
  1231.            28h     2       GS
  1232.            2ah     2       IP (reserved, ignored)
  1233.            2ch     2       CS (reserved, ignored)
  1234.            2eh     2       SP
  1235.            30h     2       SS
  1236.  
  1237. Out:
  1238.   if successful:
  1239.   ES:EDI = selector offset of modified real mode register data structure
  1240.  
  1241.   if failed:
  1242.   AX     = error code:
  1243.            8012h - linear memory unavailable (stack)
  1244.            8013h - physical memory unavailable (stack) (DPMI 1.0 only)
  1245.            8014h - backing store unavailable (stack) (DPMI 1.0 only)
  1246.            8021h - invalid value (CX too large) (DPMI 1.0 only)
  1247.  
  1248. Notes:
  1249. ) The CS:IP in the real mode register data structure is ignored by this
  1250.   function. The appropriate interrupt handler will be called based on the
  1251.   value passed in BL.
  1252.  
  1253. ) If the SS:SP fields in the real mode register data structure are zero, a
  1254.   real mode stack will be provided by the host. Otherwise the real mode SS:SP
  1255.   will be set to the specified values before the interrupt handler is called.
  1256.  
  1257. ) The flags specified in the real mode register data structure will be put on
  1258.   the real mode interrupt handler's IRET frame. The interrupt handler will be
  1259.   called with the interrupt and trace flags clear.
  1260.  
  1261. ) Values placed in the segment register positions of the data structure must
  1262.   be valid for real mode. That is, the values must be paragraph addresses, not
  1263.   protected mode selectors.
  1264.  
  1265. ) The target real mode handler must return with the stack in the same state
  1266.   as when it was called. This means that the real mode code may switch stacks
  1267.   while it is running, but must return on the same stack that it was called
  1268.   on and must return with an IRET.
  1269.  
  1270. ) When this function returns, the real mode register data structure will
  1271.   contain the values that were returned by the real mode interrupt handler.
  1272.   The CS:IP and SS:SP values will be unmodified in the data structure.
  1273.  
  1274. ) It is the caller's responsibility to remove any parameters that were pushed
  1275.   on the protected mode stack.
  1276.  
  1277. 2.17 - Function 0301h - Call Real Mode Procedure With Far Return Frame:
  1278. -----------------------------------------------------------------------
  1279.  
  1280. Simulates a FAR CALL to a real mode procedure. The called procedure must
  1281. return by executing a RETF instruction.
  1282.  
  1283. In:
  1284.   AX     = 0301h
  1285.   BH     = must be 0
  1286.   CX     = number of words to copy from the protected mode stack to the real
  1287.            mode stack
  1288.   ES:EDI = selector:offset of real mode register data structure in the
  1289.            following format:
  1290.  
  1291.            Offset  Length  Contents
  1292.            00h     4       EDI
  1293.            04h     4       ESI
  1294.            08h     4       EBP
  1295.            0ch     4       reserved, ignored
  1296.            10h     4       EBX
  1297.            14h     4       EDX
  1298.            18h     4       ECX
  1299.            1ch     4       EAX
  1300.            20h     2       CPU status flags
  1301.            22h     2       ES
  1302.            24h     2       DS
  1303.            26h     2       FS
  1304.            28h     2       GS
  1305.            2ah     2       IP
  1306.            2ch     2       CS
  1307.            2eh     2       SP
  1308.            30h     2       SS
  1309.  
  1310. Out:
  1311.   if successful:
  1312.   ES:EDI = selector offset of modified real mode register data structure
  1313.  
  1314.   if failed:
  1315.   AX     = error code:
  1316.            8012h - linear memory unavailable (stack)
  1317.            8013h - physical memory unavailable (stack) (DPMI 1.0 only)
  1318.            8014h - backing store unavailable (stack) (DPMI 1.0 only)
  1319.            8021h - invalid value (CX too large) (DPMI 1.0 only)
  1320.  
  1321. Notes:
  1322. ) The CS:IP in the real mode register data structure specifies the address of
  1323.   the real mode procedure to call.
  1324.  
  1325. ) If the SS:SP fields in the real mode register data structure are zero, a
  1326.   real mode stack will be provided by the host. Otherwise the real mode SS:SP
  1327.   will be set to the specified values before the procedure is called.
  1328.  
  1329. ) Values placed in the segment register positions of the data structure must
  1330.   be valid for real mode. That is, the values must be paragraph addresses, not
  1331.   protected mode selectors.
  1332.  
  1333. ) The target real mode procedure must return with the stack in the same state
  1334.   as when it was called. This means that the real mode code may switch stacks
  1335.   while it is running, but must return on the same stack that it was called
  1336.   on and must return with a RETF and should not clear the stack of any
  1337.   parameters that were passed to it on the stack.
  1338.  
  1339. ) When this function returns, the real mode register data structure will
  1340.   contain the values that were returned by the real mode procedure. The CS:IP
  1341.   and SS:SP values will be unmodified in the data structure.
  1342.  
  1343. ) It is the caller's responsibility to remove any parameters that were pushed
  1344.   on the protected mode stack.
  1345.  
  1346. 2.18 - Function 0302h - Call Real Mode Procedure With IRET Frame:
  1347. -----------------------------------------------------------------
  1348.  
  1349. Simulates a FAR CALL with flags pushed on the stack to a real mode procedure.
  1350. The real mode procedure must return by executing an IRET instruction or a
  1351. RETF 2.
  1352.  
  1353. In:
  1354.   AX     = 0301h
  1355.   BH     = must be 0
  1356.   CX     = number of words to copy from the protected mode stack to the real
  1357.            mode stack
  1358.   ES:EDI = selector:offset of real mode register data structure in the
  1359.            following format:
  1360.  
  1361.            Offset  Length  Contents
  1362.            00h     4       EDI
  1363.            04h     4       ESI
  1364.            08h     4       EBP
  1365.            0ch     4       reserved, ignored
  1366.            10h     4       EBX
  1367.            14h     4       EDX
  1368.            18h     4       ECX
  1369.            1ch     4       EAX
  1370.            20h     2       CPU status flags
  1371.            22h     2       ES
  1372.            24h     2       DS
  1373.            26h     2       FS
  1374.            28h     2       GS
  1375.            2ah     2       IP
  1376.            2ch     2       CS
  1377.            2eh     2       SP
  1378.            30h     2       SS
  1379.  
  1380. Out:
  1381.   if successful:
  1382.   ES:EDI = selector offset of modified real mode register data structure
  1383.  
  1384.   if failed:
  1385.   AX     = error code:
  1386.            8012h - linear memory unavailable (stack)
  1387.            8013h - physical memory unavailable (stack) (DPMI 1.0 only)
  1388.            8014h - backing store unavailable (stack) (DPMI 1.0 only)
  1389.            8021h - invalid value (CX too large) (DPMI 1.0 only)
  1390.  
  1391. Notes:
  1392. ) The CS:IP in the real mode register data structure specifies the address of
  1393.   the real mode procedure to call.
  1394.  
  1395. ) If the SS:SP fields in the real mode register data structure are zero, a
  1396.   real mode stack will be provided by the host. Otherwise the real mode SS:SP
  1397.   will be set to the specified values before the procedure is called.
  1398.  
  1399. ) The flags specified in the real mode register data structure will be put on
  1400.   the real mode procedure's IRET frame. The procedure will be called with the
  1401.   interrupt and trace flags clear.
  1402.  
  1403. ) Values placed in the segment register positions of the data structure must
  1404.   be valid for real mode. That is, the values must be paragraph addresses, not
  1405.   protected mode selectors.
  1406.  
  1407. ) The target real mode procedure must return with the stack in the same state
  1408.   as when it was called. This means that the real mode code may switch stacks
  1409.   while it is running, but must return on the same stack that it was called
  1410.   on and must return with an IRET or discard the flags from the stack with a
  1411.   RETF 2 and should not clear the stack of any parameters that were passed to
  1412.   it on the stack.
  1413.  
  1414. ) When this function returns, the real mode register data structure will
  1415.   contain the values that were returned by the real mode procedure. The CS:IP
  1416.   and SS:SP values will be unmodified in the data structure.
  1417.  
  1418. ) It is the caller's responsibility to remove any parameters that were pushed
  1419.   on the protected mode stack.
  1420.  
  1421. 2.19 - Function 0303h - Allocate Real Mode Callback Address:
  1422. ------------------------------------------------------------
  1423.  
  1424. Returns a unique real mode segment:offset, known as a "real mode callback",
  1425. that will transfer control from real mode to a protected mode procedure.
  1426. Callback addresses obtained with this function can be passed by a protected
  1427. mode program to a real mode application, interrupt handler, device driver,
  1428. TSR, etc... so that the real mode program can call procedures within the
  1429. protected mode program.
  1430.  
  1431. In:
  1432.   AX     = 0303h
  1433.   DS:ESI = selector:offset of protected mode procedure to call
  1434.   ES:EDI = selector:offset of 32h byte buffer for real mode register data
  1435.            structure to be used when calling the callback routine.
  1436.  
  1437. Out:
  1438.   if successful:
  1439.   CX:DX  = segment:offset of real mode callback
  1440.  
  1441.   if failed:
  1442.   AX     = error code:
  1443.            8015h - callback unavailable
  1444.  
  1445. Notes:
  1446. ) A descriptor may be allocated for each callback to hold the real mode SS
  1447.   descriptor. Real mode callbacks are a limited system resource. A client
  1448.   should release a callback that it is no longer using.
  1449.  
  1450. 2.20 - Function 0304h - Free Real Mode Callback Address:
  1451. --------------------------------------------------------
  1452.  
  1453. Releases a real mode callback address that was previously allocated with the
  1454. Allocate Real Mode Callback Address function (0303h).
  1455.  
  1456. In:
  1457.   AX     = 0304h
  1458.   CX:DX  = segment:offset of real mode callback to be freed
  1459.  
  1460. Out:
  1461.   if failed:
  1462.   AX     = error code:
  1463.            8024h - invalid callback address
  1464.  
  1465. Notes:
  1466. ) Real mode callbacks are a limited system resource. A client should release
  1467.   any callback that it is no longer using.
  1468.  
  1469. 2.21 - Function 0305h - Get State Save/Restore Addresses:
  1470. ---------------------------------------------------------
  1471.  
  1472. Returns the address of two procedures used to save and restore the state of
  1473. the current task's registers in the mode (protected or real) which is not
  1474. currently executing.
  1475.  
  1476. In:
  1477.   AX     = 0305h
  1478.  
  1479. Out:
  1480.   always successful:
  1481.   AX     = size of buffer in bytes required to save state
  1482.   BX:CX  = segment:offset of real mode routine used to save/restore state
  1483.   SI:EDI = selector:offset of protected mode routine used to save/restore
  1484.            state
  1485.  
  1486. Notes:
  1487. ) The real mode segment:offset returned by this function should be called
  1488.   only in real mode to save/restore the state of the protected mode registers.
  1489.   The protected mode selector:offset returned by this function should be
  1490.   called only in protected mode to save/restore the state of the real mode
  1491.   registers.
  1492.  
  1493. ) Both of the state save/restore procedures are entered by a FAR CALL with the
  1494.   following parameters:
  1495.  
  1496.   AL       = 0 to save state
  1497.            = 1 to restore state
  1498.   ES:(E)DI = (selector or segment):offset of state buffer
  1499.  
  1500.   The state buffer must be at least as large as the value returned in AX by
  1501.   INT 31h function 0305h. The state save/restore procedures do not modify any
  1502.   registers. DI must be used for the buffer offset in real mode, EDI must be
  1503.   used in protected mode.
  1504.  
  1505. ) Some DPMI hosts and VCPI/XMS/raw will not require the state to be saved,
  1506.   indicating this by returning a buffer size of zero in AX. In such cases,
  1507.   that addresses returned by this function can still be called, although they
  1508.   will simply return without performing any useful function.
  1509.  
  1510. ) Clients do not need to call the state save/restore procedures before using
  1511.   INT 31h function 0300h, 0301h, or 0302h. The state save/restore procedures
  1512.   are provided for clients that use the raw mode switch services only.
  1513.  
  1514. 2.22 - Function 0306h - Get Raw Mode Switch Addresses:
  1515. ------------------------------------------------------
  1516.  
  1517. Returns addresses that can be called for low level mode switching.
  1518.  
  1519. In:
  1520.   AX     = 0306h
  1521.  
  1522. Out:
  1523.   always successful:
  1524.   BX:CX  = segment:offset of real to protected mode switch procedure
  1525.   SI:EDI = selector:offset of protected to real mode switch procedure
  1526.  
  1527. Notes:
  1528. ) The real mode segment:offset returned by this function should be called
  1529.   only in real mode to switch to protected mode. The protected mode
  1530.   selector:offset returned by this function should be called only in protected
  1531.   mode to switch to real mode.
  1532.  
  1533. ) The mode switch procedures are entered by a FAR JMP to the appropriate
  1534.   address with the following parameters:
  1535.  
  1536.   AX    = new DS
  1537.   CX    = new ES
  1538.   DX    = new SS
  1539.   (E)BX = new (E)SP
  1540.   SI    = new CS
  1541.   (E)DI = new (E)IP
  1542.  
  1543.   The processor is placed into the desired mode, and the DS, ES, SS, (E)SP,
  1544.   CS, and (E)IP registers are updated with the specific values. In other
  1545.   words, execution of the client continues in the requested mode at the
  1546.   address provided in registers SI:(E)DI. The values specified to be placed
  1547.   into the segment registers must be appropriate for the destination mode.
  1548.   That is, segment addresses for real mode, and selectors for protected mode.
  1549.  
  1550.   The values in EAX, EBX, ECX, EDX, ESI, and EDI after the mode switch are
  1551.   undefined. EBP will be preserved across the mode switch call so it can be
  1552.   used as a pointer. FS and GS will contain zero after the mode switch.
  1553.  
  1554.   If interrupts are disabled when the mode switch procedure is invoked, they
  1555.   will not be re-enabled by the host (even temporarily).
  1556.  
  1557. ) It is up to the client to save and restore the state of the task when using
  1558.   this function to switch modes. This requires the state save/restore
  1559.   procedures whose addresses can be obtained with INT 31h function 0305h.
  1560.  
  1561. 2.23 - Function 0400h - Get Version:
  1562. ------------------------------------
  1563.  
  1564. Returns the version of the DPMI Specification implemented by the DPMI host.
  1565. The client can use this information to determine what functions are available.
  1566.  
  1567. In:
  1568.   AX     = 0400h
  1569.  
  1570. Out:
  1571.   always successful:
  1572.   AH     = DPMI major version as a binary number (VCPI/XMS/raw returns 1)
  1573.   AL     = DPMI minor version as a binary number (VCPI/XMS/raw returns 0)
  1574.   BX     = flags:
  1575.            Bits    Significance
  1576.            0       0 = host is 16bit (PMODE never runs under one of these)
  1577.                    1 = host is 32bit
  1578.            1       0 = CPU returned to V86 mode for reflected interrupts
  1579.                    1 = CPU returned to real mode for reflected interrupts
  1580.            2       0 = virtual memory not supported
  1581.                    1 = virtual memory supported
  1582.            3-15    reserved
  1583.   CL     = processor type:
  1584.            03h = 80386
  1585.            04h = 80486
  1586.            05h = 80586
  1587.            06h-ffh = reserved
  1588.   DH     = current value of master PIC base interrupt (low 8 IRQs)
  1589.   DL     = current value of slave PIC base interrupt (high 8 IRQs)
  1590.  
  1591. Notes:
  1592. ) The major and minor version numbers are binary, not BCD. So a DPMI 0.9
  1593.   implementation would return AH as 0 and AL as 5ah (90).
  1594.  
  1595. 2.24 - Function 0500h - Get Free Memory Information:
  1596. ----------------------------------------------------
  1597.  
  1598. Returns information about the amount of available memory. Since DPMI clients
  1599. could be running in a multitasking environment, the information returned by
  1600. this function should be considered advisory.
  1601.  
  1602. In:
  1603.   AX     = 0500h
  1604.   ES:EDI = selector:offset of 48 byte buffer
  1605.  
  1606. Out:
  1607.   if successful:
  1608.   buffer is filled with the following information:
  1609.  
  1610.   if failed:
  1611.   AX     = error code:
  1612.            8010h - internal resource unavailable (stack) (XMS only)
  1613.  
  1614.   Offset  Length  Contents
  1615.   00h     4       Largest available free block in bytes
  1616.   04h     2ch     Other fields only supplied by DPMI
  1617.  
  1618. Notes:
  1619. ) Only the first field of the structure is guaranteed to contain a valid
  1620.   value. Any fields that are not supported by the host will be set to -1
  1621.   (0ffffffffh) to indicate that the information is not available.
  1622.  
  1623. 2.25 - Function 0501h - Allocate Memory Block:
  1624. ----------------------------------------------
  1625.  
  1626. Allocates a block of extended memory.
  1627.  
  1628. In:
  1629.   AX     = 0501h
  1630.   BX:CX  = size of block in bytes (must be non-zero)
  1631.  
  1632. Out:
  1633.   if successful:
  1634.   BX:CX  = linear address of allocated memory block
  1635.   SI:DI  = memory block handle (used to resize and free block)
  1636.  
  1637.   if failed:
  1638.   AX     = error code:
  1639.            8010h - internal resource unavailable (stack) (XMS only)
  1640.            8012h - linear memory unavailable (DPMI 1.0/VCPI only)
  1641.            8013h - physical memory unavailable
  1642.            8014h - backing store unavailable (DPMI 1.0 only)
  1643.            8016h - handle unavailable (DPMI 1.0/XMS only)
  1644.            8021h - invalid value (BX:CX = 0)
  1645.  
  1646. Notes:
  1647. ) The allocated block is guaranteed to have at least paragraph alignment.
  1648.  
  1649. ) This function does not allocate any descriptors for the memory block. It is
  1650.   the responsibility of the client to allocate and initialize any descriptors
  1651.   needed to access the memory with additional function calls.
  1652.  
  1653. ) The allocations by this function could be paragraph, kilobyte, or page
  1654.   aligned. That is, the value you request could be rounded up to the next
  1655.   paragraph, kilobyte, or page value.
  1656.  
  1657. 2.26 - Function 0502h - Free Memory Block:
  1658. ------------------------------------------
  1659.  
  1660. Frees a memory block previously allocated with the Allocate Memory Block
  1661. function (0501h).
  1662.  
  1663. In:
  1664.   AX     = 0502h
  1665.   SI:DI  = memory block handle
  1666.  
  1667. Out:
  1668.   if failed:
  1669.   AX     = error code:
  1670.            8010h - internal resource unavailable (stack) (XMS only)
  1671.            8023h - invalid handle
  1672.  
  1673. Notes:
  1674. ) No descriptors are freed by this call. It is the client's responsibility to
  1675.   free any descriptors that it previously allocated to map the memory block.
  1676.   Descriptors should be freed before memory blocks.
  1677.  
  1678. 2.27 - Function 0503h - Resize Memory Block:
  1679. --------------------------------------------
  1680.  
  1681. Changes the size of a memory block previously allocated with the Allocate
  1682. Memory Block function (0501h).
  1683.  
  1684. In:
  1685.   AX     = 0503h
  1686.   BX:CX  = new size of block in bytes (must be non-zero)
  1687.   SI:DI  = memory block handle
  1688.  
  1689. Out:
  1690.   BX:CX  = new linear address of memory block
  1691.   SI:DI  = new memory block handle
  1692.  
  1693.   if failed:
  1694.   AX     = error code:
  1695.            8010h - internal resource unavailable (stack) (XMS only)
  1696.            8012h - linear memory unavailable (DPMI 1.0/VCPI only)
  1697.            8013h - physical memory unavailable
  1698.            8014h - backing store unavailable (DPMI 1.0 only)
  1699.            8016h - handle unavailable (DPMI 1.0/XMS only)
  1700.            8021h - invalid value (BX:CX = 0)
  1701.            8023h - invalid handle
  1702.  
  1703. Notes:
  1704. ) After this function returns successfully, the previous handle for the memory
  1705.   block is invalid and should not be used anymore.
  1706.  
  1707. ) It is the client's responsibility to update any descriptors that map the
  1708.   memory block with the new linear address after resizing the block.
  1709.  
  1710. 2.28 - Function 050Ah - Get Memory Block Size and Base:
  1711. -------------------------------------------------------
  1712.  
  1713. Returns the size and base of a memory block that was previously allocated
  1714. with the Allocate Memory Block function (0501h).
  1715.  
  1716. In:
  1717.   AX     = 050ah
  1718.   SI:DI  = memory block handle
  1719.  
  1720. Out:
  1721.   if successful:
  1722.   BX:CX  = linear address of memory block
  1723.   SI:DI  = size of memory block (bytes)
  1724.  
  1725.   if failed:
  1726.   AX     = error code:
  1727.            8010h - internal resource unavailable (stack) (XMS only)
  1728.            8023h - invalid handle
  1729.  
  1730. Notes:
  1731. ) This function is not present under DPMI 0.9.
  1732.  
  1733. 2.29 - Function 0900h - Get and Disable Virtual Interrupt State:
  1734. ----------------------------------------------------------------
  1735.  
  1736. Disables the virtual interrupt flag and returns the previous state of it.
  1737.  
  1738. In:
  1739.   AX     = 0900h
  1740.  
  1741. Out:
  1742.   always successful:
  1743.   AL     = 0 if virtual interrupts were previously disabled
  1744.   AL     = 1 if virtual interrupts were previously enabled
  1745.  
  1746. Notes:
  1747. ) AH is not changed by this function. Therefore the previous state can be
  1748.   restored by simply executing another INT 31h.
  1749.  
  1750. ) A client that does not need to know the prior interrupt state can execute
  1751.   the CLI instruction rather than calling this function. The instruction may
  1752.   be trapped by a DPMI host and should be assumed to be very slow.
  1753.  
  1754. 2.30 - Function 0901h - Get and Enable Virtual Interrupt State:
  1755. ---------------------------------------------------------------
  1756.  
  1757. Enables the virtual interrupt flag and returns the previous state of it.
  1758.  
  1759. In:
  1760.   AX     = 0901h
  1761.  
  1762. Out:
  1763.   always successful:
  1764.   AL     = 0 if virtual interrupts were previously disabled
  1765.   AL     = 1 if virtual interrupts were previously enabled
  1766.  
  1767. Notes:
  1768. ) AH is not changed by this function. Therefore the previous state can be
  1769.   retstored by simply executing another INT 31h.
  1770.  
  1771. ) A client that does not need to know the prior interrupt state can execute
  1772.   the STI instruction rather than calling this function. The instruction may
  1773.   be trapped by a DPMI host and should be assumed to be very slow.
  1774.  
  1775. 2.31 - Function 0902h - Get Virtual Interrupt State:
  1776. ----------------------------------------------------
  1777.  
  1778. Returns the current state of the virtual interrupt flag.
  1779.  
  1780. In:
  1781.   AX     = 0902h
  1782.  
  1783. Out:
  1784.   always successful:
  1785.   AL     = 0 if virtual interrupts are disabled
  1786.   AL     = 1 if virtual interrupts are enabled
  1787.  
  1788. Notes:
  1789. ) This function should be used in preference to the PUSHF instruction to
  1790.   examine the interrupt flag, because the PUSHF instruction returns the
  1791.   physical interrupt flag rather than the virtualized interrupt flag. On some
  1792.   DPMI hosts, the physical interrupt flag will always be enabled, even when
  1793.   the hardware interrupts are not being passed through to the client.
  1794.  
  1795. 2.32 - Function FFFFh - Special Fluffy Magical Function:
  1796. --------------------------------------------------------
  1797.  
  1798. Does special fluffy magical things.
  1799.  
  1800. In:
  1801.   AX     = ffffh
  1802.  
  1803. Out:
  1804.   if successful:
  1805.   AX     = 1234h (normal fluffy magical number)
  1806.   BX     = 56ijh (special fluffy magical number)
  1807.   CX     = 89abh (nothing really special)
  1808.   DX     = cdefh (again, just a boring number)
  1809.   EX     = return value from beyond
  1810.   FX     = an acronym for 'effects'
  1811.   GX     = huh?
  1812.   HX     = size of special fluffy magical buffer
  1813.  
  1814.   if failed:
  1815.   AX     = error code:
  1816.            8001h - get a grip on reality!
  1817.  
  1818. Notes:
  1819. ) The special fluffy magical buffer must not exceed the special fluffy magical
  1820.   constant in size, which is defined in the special fluffy magical place.
  1821.  
  1822. ) Well, maybe it exists... Maybe if you try calling it many many many many
  1823.   many many many many times in a row it will succeed.
  1824.  
  1825. ------------------------------------------------------------------------------
  1826. 3 - Miscellenaous:
  1827. ------------------
  1828.  
  1829.   Some final things about PMODE, including some low level tech info if you are
  1830. just curious.
  1831.  
  1832. 3.0 - Updates:
  1833. --------------
  1834.  
  1835.   Here are the changes from any previous versions of PMODE 3.0.
  1836.  
  1837. PMODE 3.0:
  1838. ) First release of PMODE 3.0.
  1839.  
  1840. PMODE 3.01:
  1841. ) Slightly optimized VCPI/XMS/raw mode switching routines.
  1842.  
  1843. ) Fixed bug with INT 31h translation functions 0300h, 0301h, and 0302h not
  1844.   returning correct flags in the register structure.
  1845.  
  1846. ) Fixed bug with software INT redirection calls clearing the interrupt flag.
  1847.  
  1848. PMODE 3.02:
  1849. ) Decreased VCPI mode switching free stack space requirement to 32 bytes.
  1850.  
  1851. PMODE 3.03:
  1852. ) Fixed real mode INT 15h in raw mode, now always returns with the carry flag
  1853.   clear as it should.
  1854.  
  1855. PMODE 3.04:
  1856. ) Fixed a stupid bug with INT 31h AX=03??h requiring the high word of ECX to
  1857.   be clear that someone pointed out to me.
  1858.  
  1859. ) Added (actually just documented) low level access to PMODE's internal real
  1860.   mode and protected mode stacks.
  1861.  
  1862. PMODE 3.05:
  1863. ) Fixed INT 31h function 0204h not returning the high word of EDX correctly.
  1864.  
  1865. ) Fixed INT 31h function 0301h putting flags on the real mode return stack.
  1866.   This was a stupid one, it was not there from the beginning, but was created
  1867.   when I fixed the INT 31h AX=03??h bug in version 3.04 (I have accordingly
  1868.   knocked my head into the wall a few times for this... sorry)...
  1869.  
  1870. PMODE 3.06:
  1871. ) Added control of the order of DPMI/VCPI detection.
  1872.  
  1873. ) Changed interrupt redirection method (means nothing to your code).
  1874.  
  1875. ) PMODE no longer returns its own code selector (it wasn't much of an
  1876.   optimization really).
  1877.  
  1878. ) Changed VCPI memory allocation slightly.
  1879.  
  1880. PMODE 3.07:
  1881. ) Someone please send me a gun so that I may shoot myself. For the second time
  1882.   I have corrected a bug that I introduced in an update. The VCPI memory
  1883.   system just did not work in v3.06. Well kiddies, what can we learn from this
  1884.   little experience? (Besides that I'm an ideot). Maybe the next time we
  1885.   should test something before we put it out... (Actually I usually do, but I
  1886.   was feeling especially lazy when putting together v3.06).
  1887.  
  1888. 3.1 - Glossary:
  1889. ---------------
  1890.  
  1891. Bottom up allocation - A method of extended memory allocation which relies on
  1892.   control blocks specifying the start of free extended memory. This is the
  1893.   VDISK extended memory allocation scheme.
  1894.  
  1895. Client - A program which uses DPMI INT 2fh and INT 31h services to run in
  1896.   protected mode.
  1897.  
  1898. CPL, Current Privilege Level - The privilege level of the currently executing
  1899.   code.
  1900.  
  1901. Descriptor - An 8 byte structure which defines a segment type, its base
  1902.   address and limit, and the type of access allowed to it.
  1903.  
  1904. DPL, Descriptor Privilege Level - The privilege level of a descriptor.
  1905.   Descriptor protection is based on certain rules of the CPL and DPL of a
  1906.   descriptor that code may want to access.
  1907.  
  1908. DPMI, DOS Protected Mode Interface - An interface for protected mode DOS
  1909.   programs to manage memory, interrupts, exceptions, debugging registers, and
  1910.   coprocessor emulation in a well behaved manner which allows them to coexist
  1911.   with other protected mode programs and operating systems.
  1912.  
  1913. Exception - An interrupt that occurs because of some violation of protection
  1914.   rules.
  1915.  
  1916. Extended memory - Memory which lies above the 1M boundary and can only be
  1917.   addressed in protected mode.
  1918.  
  1919. GDT, Global Descriptor Table - A descriptor table which can contain many types
  1920.   of descriptors besides the regular code and data descriptors. This can
  1921.   include TSS descriptors and LDT descriptors.
  1922.  
  1923. Host - A program which provides DPMI protected mode services.
  1924.  
  1925. IDT, Interrupt Descriptor Table - A descriptor table which contains the
  1926.   gate descriptors to the handlers for the 256 interrupts.
  1927.  
  1928. LDT, Local Descriptor Table - A descriptor table which usually contains all
  1929.   the descriptors of a particular task. Each task in a 386 multitasking system
  1930.   can have its own LDT whereas there is only one GDT for the entire system.
  1931.  
  1932. Linear memory - Address space rather than actual physical RAM of ROM.
  1933.  
  1934. Page - A 4k chunk of memory. The 80386 can map any 4k chunk of physical memory
  1935.   to any linear address. There are also some protection rules that can apply
  1936.   to pages, such as read-only, or privilege level checking on access.
  1937.  
  1938. Page Directory - Sort of a master page table which maps page tables instead of
  1939.   pages.
  1940.  
  1941. Page Table - A 4k table containing 1024 entries for pages. Each page table
  1942.   maps 4 megabytes of linear memory to physical memory.
  1943.  
  1944. Physical memory - The actual physical memory present in a system.
  1945.  
  1946. Privilege level - A numeric value representing the freedom of system access
  1947.   and how much protection applies to code. This value ranges from
  1948.   0 (most free (godlike)) to 3 (least free (lowly slave)).
  1949.  
  1950. RPL, Requestor Privilege Level - The privilege level code requests for a
  1951.   specific selector access. It is contained in the low two bits of the
  1952.   selector.
  1953.  
  1954. Segment - A specific linear chunk of memory. In real mode, segments are
  1955.   limited to the first megabyte of memory and are always 64k in length. In
  1956.   protected mode, a segment can start anywhere in the entire 4 gigabyte
  1957.   address space of the 80386 and can be that long.
  1958.  
  1959. Selector - An index in protected mode into a descriptor table. Selectors are
  1960.   used in place of segments in protected mode in the segment registers.
  1961.  
  1962. Top down allocation - A method of extended memory management which relies on
  1963.   the BIOS INT 15h function 88h. A program which needs to allocate extended
  1964.   memory will hook INT 15h and return a smaller extended memory size. The
  1965.   program is then free to use the memory between the previous top of extended
  1966.   memory and what it returns as the top of extended memory without worrying
  1967.   about other programs overwriting its extended memory.
  1968.  
  1969. TSS, Task State Segment - A special memory structure used in task switching
  1970.   and protection.
  1971.  
  1972. V86 mode - Actually it is protected mode, running at a privilege level of 3.
  1973.   Segment registers are used in the same manner as in real mode, with segment
  1974.   addresses rather than selectors. The advantage is that paging and other
  1975.   protected tasks can be active, which includes other V86 mode tasks. The
  1976.   disadvantage is that it is slower than real mode.
  1977.  
  1978. VCPI, Virtual Control Program Interface - The predecessor to DPMI. VCPI
  1979.   extends the EMS interface to allow DOS programs to run in protected mode
  1980.   in the presence of EMS emulators or other 80386 control programs.
  1981.  
  1982. Virtual memory - Extra memory beyond the actual physical memory present in a
  1983.   system. There is not really any more physical memory in the system, but an
  1984.   operating system or DPMI host can give that illusion by swapping the
  1985.   contents of physical memory to and from a disk and mapping that physical
  1986.   memory to different linear addresses.
  1987.  
  1988. XMS, eXtended Memory Specification - A handle based extended memory management
  1989.   interface.
  1990.  
  1991. 3.2 - Differences between modes:
  1992. --------------------------------
  1993.  
  1994. Some differences between DPMI, VCPI, XMS, and raw protected mode:
  1995.  
  1996. ) DPMI:
  1997.     Client descriptors reside in a LDT.
  1998.   VCPI/XMS/raw:
  1999.     Client descriptors reside in the GDT.
  2000.  
  2001. ) DPMI:
  2002.     Code runs at CPL 3.
  2003.   VCPI/XMS/raw:
  2004.     Code runs at CPL 0. (Much faster)
  2005.  
  2006. ) DPMI/VCPI:
  2007.     Real mode calls are executed in V86 mode.
  2008. ) XMS/raw:
  2009.     Real mode calls are executed in real mode. (Much faster)
  2010.  
  2011. ) DPMI/VCPI:
  2012.     Paging is enabled.
  2013.   XMS/raw:
  2014.     Paging is disabled. (Not really very much faster, but what the hell)
  2015.  
  2016. ) DPMI:
  2017.     IRET(D) and POPF(D) may not affect the interrupt flag. PUSHF(D) may not
  2018.     store the interrupt flag.
  2019.   VCPI/XMS/raw:
  2020.     IRET(D) and POPF(D) affect the real interrupt flag. PUSHF(D) stores the
  2021.     real interrupt flag.
  2022.  
  2023. ) DPMI:
  2024.     INTs 1Ch, 23h, and 24h from real mode are sent to protected mode first.
  2025.     This means if a protected mode handler is installed for these interrupts,
  2026.     it will get control.
  2027. ) VCPI/XMS/raw:
  2028.     DPMI dox are not too clear on the method these interrupts are called in.
  2029.     Callbacks I would guess. But I am too lazy to investigate. And frankly, I
  2030.     don't give a shit. So the VCPI/XMS/raw kernel does not support this.
  2031.  
  2032. ) DPMI:
  2033.     Seperates exceptions from other low interrupts and IRQs. That is, an
  2034.     exception 8 would never erroneously go to the handler for IRQ 0.
  2035. ) VCPI/XMS/raw:
  2036.     Hey, exceptions are bad, you should not be getting them in the first
  2037.     place. Reprogramming the interrupt controllers or running the client code
  2038.     at a lower privilege is not worth the slowdown for me.
  2039.  
  2040. ) DPMI:
  2041.     Theoretically, DPMI may refuse a request to set a segment limit to 4G.
  2042.     I have not yet found a DPMI that will refuse this. They all do protection
  2043.     at the paging level. And a high limit is necessary for flat mode and
  2044.     negative offsets.
  2045. ) VCPI/XMS/raw:
  2046.     There is no protection, no segment limit or base address will ever be
  2047.     denied.
  2048.  
  2049. ) DPMI:
  2050.     Memory allocation is almost always page granular, but not necessarily.
  2051.   VCPI:
  2052.     Memory allocation is page granular (4k chunks).
  2053.   XMS:
  2054.     Memory allocation is kilobyte granular.
  2055.   raw:
  2056.     Memory allocation is paragraph granular.
  2057.  
  2058. ) DPMI/VCPI:
  2059.     Low memory linear addresses may or may not be the actual physical
  2060.     addresses. Extended memory addresses are almost sure not to be.
  2061.   XMS/raw:
  2062.     All linear addresses are physical addresses.
  2063.  
  2064. 3.3 - Notes:
  2065. ------------
  2066.  
  2067.   Here are some misc and low level technical details about PMODE and some
  2068. points I want to emphasize. Some of them may seem very obscure, with no real
  2069. need to list. But for the sake of thorough documentation, they are here:
  2070.  
  2071. ) In protected mode, ESP must always be the stack pointer. Meaning, even if
  2072.   using a 16bit stack segment, the high word of ESP MUST be 0.
  2073.  
  2074. ) When calling the raw mode switching routine to switch into protected mode,
  2075.   you must supply the full ESP and EIP. Even if the stack or code segments
  2076.   being switched to are 16bit.
  2077.  
  2078. ) If the call to init protected mode was from a segment other than PMODE_TEXT
  2079.   under DPMI, and a descriptor can not be allocated for that code segment,
  2080.   immediate termination results. But this should never happen. A DPMI host
  2081.   that can not supply even one descriptor to its protected mode clients defies
  2082.   logic. But for the sake of covering all possible screw-ups, this condition
  2083.   is checked for.
  2084.  
  2085. ) DPMI 1.0/VCPI/XMS/raw will reload any segment registers for which the
  2086.   descriptor is changed through an INT 31h function. DPMI 0.9 does not.
  2087.   (Actually it does, through pushing and then popping any segment registers
  2088.   it uses. But it is not guaranteed to reload any or all of them).
  2089.  
  2090. ) DPMI 1.0/VCPI/XMS/raw will zero any segment registers freed with INT 31
  2091.   function 0001h. DPMI 0.9 may or may not.
  2092.  
  2093. ) I dont know about DPMI with respect to reloading or freeing a selector which
  2094.   is currently loaded into SS, but the VCPI/XMS/raw system will not reload or
  2095.   zero SS. You should not be modifying your stack or code descriptor as you
  2096.   are using it. This could be bad, even if the INT 31h were handled through a
  2097.   task gate (which would be slow).
  2098.  
  2099. ) Remember that DPMI 0.9 does not return error codes as DPMI 1.0/VCPI/XMS/raw
  2100.   do.
  2101.  
  2102. ) Reasons for calls to real mode executing in actual real mode rather than
  2103.   V86 mode (XMS/raw):
  2104.   ) V86 call system can not be used under VCPI very successfully. (Yes, VCPI
  2105.     runs its real mode in V86. But VCPI MUST be in control in this case.)
  2106.   ) Real mode runs faster than V86 mode.
  2107.   ) INT 15h and XMS extended memory functions will work.
  2108.   ) Other protected mode programs that run DOS functions in real mode will
  2109.     work.
  2110.   ) It is faster to switch between protected/real mode than protected/V86.
  2111.  
  2112. ) Use LAR to find out the current CPL for setting descriptor access right.
  2113.  
  2114. ) You must always set the present bit when setting descriptor access rights.
  2115.  
  2116. ) Under the VCPI/XMS/raw system, the AVL bit of descriptors is used to keep
  2117.   track of free and used descriptors. The value you pass for this bit when
  2118.   setting descriptor access rights will be ignored.
  2119.  
  2120. ) When switching modes using the raw switching routines, make sure there is
  2121.   some space on both stacks (real and protected). Specific DPMI requirements
  2122.   may vary, but 32 bytes is enough for VCPI/XMS/raw.
  2123.  
  2124. ) In protected mode, remember to use IRETD, not IRET. When DPMI documentation
  2125.   refers to using IRET, it is actually referring to the 32bit version of the
  2126.   instruction under 32bit systems, which is IRETD.
  2127.  
  2128. ) Remember that free memory information is just advisory. A TSR or another
  2129.   task in a multitasking system might grab some memory in between a call to
  2130.   INT 31h function 0500h and INT 31h function 0501h, even if you disable
  2131.   interrupts.
  2132.  
  2133. ) The _pm_? variables are not checked for validity. So don't set them outside
  2134.   reasonable bounds. For example, don't ask for 20h real mode stacks of size
  2135.   1000h paragraphs. This is two megabytes of real mode stack space. This is
  2136.   way too much, considering that all real mode available low memory
  2137.   encompasses 640k.
  2138.  
  2139. ) You should allocate memory in large blocks. Memory space is subject to
  2140.   fragmentation. Although you can help the situation a little under VCPI by
  2141.   setting a high number of page tables. This will not increase the physical
  2142.   memory available, but it will increase the address space available to put
  2143.   that memory into linear chunks.
  2144.  
  2145. ) I tried to balance clean, well designed code, with size and speed. True,
  2146.   some things are not as absolutely optimal as they can be. But the source is
  2147.   right here. Very clean and commented. If you truly need those last ounces of
  2148.   speed, feel free to modify it (this does not free you from the obligation of
  2149.   crediting me for it).
  2150.  
  2151. ) I can not control what DPMI does. But under XMS/raw, code in protected mode
  2152.   runs at the fastest speed possible. That is, there is no privilege checking
  2153.   to get in the way. No exception will rip control away from sensitive
  2154.   instructions. Not even paging, with its memory references every time a page
  2155.   table entry is not found in the TLB. Under VCPI, all of this applies except
  2156.   the paging. Which really isn't that bad.
  2157.  
  2158. ) Under VCPI, free memory information is validated in function 0500h by
  2159.   actually allocating that memory and releasing it before passing the
  2160.   information to your program. This because under some multitasking systems,
  2161.   the VCPI function for getting the memory available may return information
  2162.   for the whole system. While the multitasking system may impose allocation
  2163.   limits on the specific task your code is part of.
  2164.  
  2165. ) Under VCPI/XMS/raw, INT 31h function 0500h will return only the first field
  2166.   of the buffer set. All the other fields will be set to 0ffffffffh.
  2167.  
  2168. ) Under VCPI/XMS/raw, an allocate descriptor INT 31h function 0000h called
  2169.   with CX = 0 will return error 8021h. DPMI dox dont state this, and I dont
  2170.   know if DPMI returns an error on CX = 0.
  2171.  
  2172. ) INT 31h functions 0300h, 0301h, and 0302h will always inform you if there is
  2173.   not enough real mode stack space. But and IRQ or INT redirection can not.
  2174.   In this case, the PC speaker will be turned on, and the machine will be
  2175.   hung. This is better than allowing it to overrun data below it with
  2176.   unpredictable results. And hey, I dont need no stinkin debug code cluttering
  2177.   up my nice and pretty extender. I just need it to tell me in case something
  2178.   like this happenes. If you want debug code, go and hack it in yourself.
  2179.  
  2180. ) DPMI dox dont state this, but the alias descriptor INT 31h function 000ah
  2181.   creates is always an expand-up and writeable data descriptor. No matter what
  2182.   type the source descriptor is.
  2183.  
  2184. ) You should limit yourself to allocating as few individual memory blocks as
  2185.   possible. Under XMS, there is usually a strict limit on how many blocks can
  2186.   be allocated (normally 32).
  2187.  
  2188. ) DPMI dox state that the field between EBP and EBX should be zero upon an
  2189.   INT 31h function 0300h, but is ignored by functions 0301h and 0302h. That is
  2190.   just a stupid typo, the field will be ignored by function 0300h.
  2191.  
  2192. ) Under XMS an extra 15 bytes will be allocated for possible aligning of the
  2193.   XMS memory block on a paragraph. Though an XMS block will probably already
  2194.   be aligned on at least a paragraph boundary, this is not defined in the XMS
  2195.   standard. And to keep the possibility of problems at nil, this is done.
  2196.  
  2197. ) Be aware that memory allocation functions under XMS use real mode calls and
  2198.   real mode stack space defined with _pm_rmstacklen and _pm_rmstacks. If there
  2199.   is not enough stack space for the call to the real mode XMS driver, error
  2200.   code 8010h (resource unavailable) will be returned.
  2201.  
  2202. ) If an XMS memory lock fails, which is used in memory allocation functions,
  2203.   error 8010h will be returned. A memory lock failure is not due to memory not
  2204.   being available. But rather, some internal XMS crap. But it should never
  2205.   happen anyway.
  2206.  
  2207. ) The raw system checks both INT 15h and the VDISK low to high extended memory
  2208.   allocation scheme to get its available extended memory area.
  2209.  
  2210. ) The raw system allocates extended memory on an as-needed basis from the top
  2211.   down. INT 15h function 88h is hooked and the total amount of memory
  2212.   allocated using the kernel function 0501h is subtracted from the amount of
  2213.   memory returned from the previous INT 15h handler. This is so that you can
  2214.   execute other protected mode programs from within your programs and they
  2215.   will have extended memory available (if you left any).
  2216.  
  2217. ) A protected mode IRQ handler or real mode callback must return on the same
  2218.   stack it was called with.
  2219.  
  2220. ) A real mode routine called with functions 0300h, 0301h, or 0302h must return
  2221.   on the same stack it was called with.
  2222.  
  2223. ) You should make no assumptions about the low memory protected mode data area
  2224.   needed by PMODE. It can range from very small to very large. And if a DPMI
  2225.   host is present, it is unpredictable.
  2226.  
  2227. ) Make sure you do not access, read or write, extended memory outside the
  2228.   blocks you allocate. Even if there is no physical memory there, you will
  2229.   probably get exceptions under DPMI/VCPI.
  2230.  
  2231. ) When setting descriptor access rights, remember that the B bit of stack
  2232.   descriptors determines whether PUSHes and POPs use SP (B=0) or ESP (B=1).
  2233.  
  2234. ) If you enable interrupts in a callback, you MUST assume DS is no longer
  2235.   valid. Even if you are sure your callback will not be re-entered. This is
  2236.   because PMODE uses the same DS selector for ALL real mode callbacks.
  2237.  
  2238. ) The reserved field between EBP and EBX in the register structure used during
  2239.   a callback is used by PMODE to preserve the high word of ESP for real mode.
  2240.  
  2241. ) You should assume the INT 31h extended memory functions to be slow.
  2242.   Especially under VCPI, where a call has to be made to the VCPI server for
  2243.   each 4k of memory allocated or freed, and two calls for each 4k verified.
  2244.  
  2245. ) Under PMODE, software INT redirection calls only pass back the carry,
  2246.   parity, aux, zero, sign, and overflow flags from the real mode interrupt
  2247.   handler.
  2248.  
  2249. ) When using the raw mode switching routines, keep in mind that they use some
  2250.   stack space on both the real mode and protected mode stacks. Never set the
  2251.   destination stack to the same location in memory as the stack being switched
  2252.   from.
  2253.  
  2254. ------------------------------------------------------------------------------
  2255. 3.4 - Final word:
  2256. -----------------
  2257.  
  2258.   I like this latest PMODE a lot. For an extender, it is clean, solid, fast,
  2259. and small. It is not limited to assembly code. It does not need control at
  2260. startup, but may be initialized at any time. It can be turned into basically
  2261. any type of extender. It can work with high level languages. You will probably
  2262. also like it because it is free, and the source code is provided. The DPMI
  2263. interface assures portability and long life. Enjoy protected mode, and
  2264. remember the credits.
  2265.  
  2266.                                                 L8r...
  2267.                                                 Tran...
  2268.  
  2269.